sqlalchemy 和 flask-sqlalchemy 分表

对于 sqlalchemy 和 flask-sqlalchemy 分表的方案,网上的资料很少,经过google和自己项目的尝试,找到比较合适的解决的方案。 下面的 user 表根据用户的ID % 100 分布在 0 - 99 张表中。 另外,如果要处理分库的话,只需要在model中加入 __bind_key__,等于分库的规则。 sqlalchemy 分表示例: #!/usr/bin/env python # -*- coding: utf-8 -*- from sqlalchemy import Column, Integer, String, BigInteger, SmallInteger from sqlalchemy import create_engine from sqlalchemy.orm import Session from sqlalchemy.ext.declarative import declarative_base Base = declarative_base() class UserData(object): _mapper = {} @staticmethod def model(user_id): table_index = user_id % 100 class_name = 'user_%d' % table_index ModelClass = UserData._mapper.get(class_name, None) if ModelClass is None: ModelClass = type(class_name, (Base,), dict( __module__=__name__, __name__=class_name, __tablename__='user_%d' % table_index, id=Column(BigInteger, primary_key=True), name=Column(String(255)), picture=Column(String(255)), valid=Column(SmallInteger), utime=Column(Integer), ctime=Column(Integer) )) UserData._mapper[class_name] = ModelClass cls = ModelClass return cls if __name__ == '__main__': engine = create_engine('mysql+pymysql://%s:%s@%s:%s/%s' % ('root', 'root', '127.0.0.1', '3306', 'test'), encoding='utf8') Base.metadata.create_all(engine) session = Session(engine) # user_id = 100001 user_id = 1000001 user = UserData.model(user_id) result_1 = session.query(user).count() result_2 = session.query(user).filter(user.name == "test", user.valid == 0).all() result_3 = session.query(user).filter_by(name="test", valid=0).all() print(result_1, result_2, result_3) flask-sqlalchemy 分表示例: #!/usr/bin/env python # -*- coding: utf-8 -*- from flask import Flask, jsonify from flask_sqlalchemy import SQLAlchemy app = Flask(__name__) app.config.from_pyfile('flask-sqlalchmey-sharding.cfg') db = SQLAlchemy(app) class User(object): '''用户分表''' _mapper = {} @staticmethod def model(user_id): table_index = user_id % 100 # db_index = int((user_id % 100) / 25) class_name = 'user_%d' % table_index ModelClass = User._mapper.get(class_name, None) if ModelClass is None: ModelClass = type(class_name, (db.Model,), { '__module__': __name__, '__name__': class_name, '__tablename__': 'user_%d' % table_index, 'id': db.Column(db.BigInteger, primary_key=True), 'name': db.Column(db.String(100)), 'phone': db.Column(db.String(20)), 'status': db.Column(db.SmallInteger, default=0), 'ctime': db.Column(db.Integer, default=0), 'utime': db.Column(db.Integer, default=0) }) User._mapper[class_name] = ModelClass cls = ModelClass return cls @app.route('/ /test', methods=['GET', 'POST']) def test(user_id): user = User.model(user_id) count = user.query.filter_by(id=user_id).count() item = user.query.filter(user.id == user_id, user.status == 0).first() # default name = item.name if item else "default" return jsonify(count=count, name=name) if __name__ == '__main__': app.run() flask-sqlalchmey-sharding.cfg 文件: SQLALCHEMY_DATABASE_URI = = 'mysql+pymysql://root:root@localhost:3306/test' SQLALCHEMY_ECHO = True SECRET_KEY = '\xfb\x12\xd ...

阅读全文 »

flask+sqlalchemy+postgresql 异步方案

flask+sqlalchemy+postgresql 异步方案的Github 地址: https://github.com/sixu05202004/async-flask-sqlalchemy-postgresql 使用说明: 安装所需的插件: pip install -r requirements.txt 需要在postgresql中创建数据库 test_asyn 运行 python app.py -c 用来创建测试的表; 运行 python app.py 来启动服务器,运行 python client 来测试 结果如下:: localhost:async-flask-sqlalchemy-postgresql sixu05202004$ python client.py Sending 5 requests for http://localhost:8080/test/postgres/... @ 5.05s got response [200] @ 5.05s got response [200] @ 5.05s got response [200] @ 5.05s got response [200] @ 5.05s got response [200] = 5.06s TOTAL SUM TOTAL = 5.06s 注意: 1.config.py 中需要修改测试数据库的用户名和密码,并且可以修改pool_size的数量; 2.python client.py num,比如:python client.py 100可以用来模拟更多的连接; 3.如果python client.py num中得num数大于config.py中的SQLALCHEMY_POOL_SIZE = 100时候,我们会发现有些数据库连接又存在阻塞的情况。 比如,我们把SQLALCHEMY_POOL_SIZE改成10,使用python client.py 30来测试,结果如下:: localhost:async-flask-sqlalchemy-postgresql sixu05202004$ python client.py 30 Sending 30 requests for http://localhost:8080/test/postgres/... @ 5.07s got response [200] @ 5.07s got response [200] @ 5.08s got response [200] @ 5.09s got response [200] @ 5.09s got response [200] @ 5.13s got response [200] @ 5.12s got response [200] @ 5.12s got response [200] @ 5.13s got response [200] @ 5.19s got response [200] @ 5.19s got response [200] @ 5.19s got response [200] @ 5.19s got response [200] @ 5.19s got response [200] @ 5.19s got response [200] @ 5.19s got response [200] @ 5.19s got response [200] @ 5.20s got response [200] @ 5.20s got response [200] @ 5.20s got response [200] @ 10.14s got response [200] @ 10.15s got response [200] @ 10.15s got response [200] @ 10.24s got response [200] @ 10.24s got response [200] @ 10.24s got response [200] @ 10.24s got response [200] @ 10.25s got response [200] @ 10.25s got response [200] @ 10.26s got response [200] = 10.28s TOTAL SUM TOTAL = 10.28s 这是因为 连接数 》SQLALCHEMY_POOL_SIZE + SQLALCHEMY_MAX_OVERFLOW ,我们可以通过一些设置来避免这种情况(NullPool ),但是实际上 postgresql 规定了最大连接数,这个是无法避免的,因此上述的设置最好不要使用 ...

阅读全文 »