在多区域情况下,每个区域都要一套完整的数据体系。然而管控层一般都是统一的,需要经常按照区域识别查询数据库。Sqlalchemy 提供了多库绑定功能,参考实现如下:
from flask import Flask from flask_sqlalchemy import SQLAlchemy from sqlalchemy import MetaData # 多个数据库连接配置信息 SQLALCHEMY_BINDS = { 'zbs': 'mysql://sharp:sharp@172.17.0.1:3306/zbs', 'sharp': 'mysql://sharp:sharp@172.17.0.1:3306/sharp', } app = Flask(__name__) app.config['SQLALCHEMY_BINDS'] = SQLALCHEMY_BINDS app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = False # 由于使用了 Flask,这里就直接一起搞了 db = SQLAlchemy(app) class ZbsVolume(db.Model): # 指定要连接的数据库 __bind_key__ = 'zbs' # 指定对应的表名,默认是类名,这莫办法的事 __tablename__ = 'volume' # 不然会爆表名冲突,无法初始化 metadata = MetaData() id = db.Column(db.String(36), primary_key=True) volume_type_name = db.Column(db.String(255)) class SharpVolume(db.Model): __bind_key__ = 'sharp' __tablename__ = 'volume' metadata = MetaData() id = db.Column(db.String(36), primary_key=True) volume_type_name = db.Column(db.String(255))
定义好ORM,那使用就简单了,参考如下:
# 初始化数据库连接 db.create_all() ZbsVolume.query.filter_by(id='fake').first() # 新增一个 query = ZbsVolume(id=line, volume_type_name='hdd.std2) db.session.add(query)
只有1个表两个库,这么写写也直观,如果要查 N 个表,又有 M 个库,这真成了无感情的机器人了。
这时候是不是想起来了类也是可以创建的,一个简单的元类不就行了,那我们就试试看
定义一个 meta.py 文件,用来存在原始表信息
from sqlalchemy import MetaData, Column, String, Integer VolumeMeta = { '__tablename__': 'volume', '__table_args__': {'extend_existing': True}, 'metadata': MetaData(), 'id': Column(String(36), primary_key=True), 'volume_type_name': Column(String(255)), }
定义 model.py,用来创建 model
class ModelFactor(object): def __init__(self): self.cache = {} self.regions = config.ZBS_MYSQL_MAP.keys() self.meta_dict = { 'Volume': VolumeMeta, 'fake1": FakeMeta, } @classmethod def make_model_key(cls, region, model): return '%s_%s' % (region, model) def create_model(self, region, model): if model not in self.meta_dict: logger.error("model <%s> not define" % model) return None if region not in self.regions: logger.error("region <%s> not define" % region) return None db = init_db() meta = self.meta_dict[model] meta['__bind_key__'] = region logger.info("Now create model <%s_%s>" % (region, model)) return type(model, (db.Model,), meta) def select_model(self, region, model): key = self.make_model_key(region, model) if key not in self.cache: model = self.create_model(region, model) if model: self.cache[key] = model else: model = self.cache[key] return model
使用
model_factor = ModelFactor() model = model_factor.select_model(region, 'Volume') # 开始 orm 操作