a1.sqlalchemy-研究

本文深入探讨SQLAlchemy与Flask结合使用的技巧,包括数据库表的创建与更新、事务操作详解,以及在大规模数据处理中如何优化查询效率。文章还对比了SQLAlchemy与flask-sqlalchemy的区别,提供了一系列实用的代码示例。

Sqlalchemy And Flask-Sqlalchemy

使用sqlalchemy时,先搞明白:

  • sqlalchemy和flask-sqlalchemy不相等。flask-sqlalchemy是一个flask的扩展,简化了在flask中使用sqlalchemy的操作。
  • sqlalchemy提供了高层orm,也提供了使用数据库原生sql的底层功能。

sqlalchemy使用

  • db.create_all()可以用来创建表,若表已存在,那么其不会进行创建或者更新。但是在修改模型后要把改动应用到现有的数据库中,粗暴的方式为先删除表,再重新创建。db.drop_all()/db.create_all()因此,可以用Django的那套orm来创建表,sqlalchemy只用来操作表内的数据。

事务操作(数据库会话也成为事务)

  • 通过数据库会话管理对数据库所做的改动。sqlalchemy中用db.session标识
    • db.session.add() 添加到会话
    • db.session.flush()刷新会话,这里可以拿到对象的id,对应的数据已到数据库缓存中,只是还未提交。
    • db.session.commit() 提交会话
  • 数据库会话能保证数据库的一致性。
  • 提交操作使用原子方式把会话中的对象全部写入数据库。如果写入的过程发生了错误,整个会话都会失效。(只要把相关的改动放在会话中提交,就能避免因部分更新导致的数据库的不一致,就能完成事务的操作)
  • db.session.rollback() 数据库会话的回滚。调用后,添加到数据库会话的所有对象都会还原到他们在数据库时的状态。

db.session.flush详解

通过query可以拿到数据,执行mysql语句同理也可以,但是这个只限于在当前连接的缓存内体现,数据还未被持久化到数据库文件。别的账户连接,是看不到这个数据的。也就是数据库没有这条数据,但是在缓存内是有这个数据的。

# TODO 试验db.session.flush()
@ns.route('/test')
class test(Resource):
    def get(self):
        # 最后一个id是122
        count_obj = dbm.TaskCount()
        count_obj.date = '1111-11-11'
        count_obj.total_count = 11
        count_obj.complete_count = 11
        count_obj.task_template_id = 646
        db.session.add(count_obj)
        db.session.flush()
        logger.info(">>>>>>>>> flush_id >>>>>%s"%count_obj.id)
        query_obj = dbm.TaskCount.query.filter_by(id=count_obj.id).first()
        if query_obj:
            logger.info(".....%s"%query_obj.id)
            logger.info('......data..... %s'%query_obj.date)
        temp_id = count_obj.id
        query2 = db.session.execute("select * from patrol_inspect_task_count where id=:id", {'id': temp_id}).fetchall()
        logger.info('******** query_2 ********* %s'%query2)
        return 'yes!'


# 得到的结果(基于mysql的缓存,预提交机制autocommit机制的设置)

# flush可以拿到id
>>>>>>>>> flush_id >>>>>125

.....125
......data..... 1111-11-11

# 直接执行sql语句拿到的结果
******** query_2 ********* [(125, u'1111-11-11', 11, 11, 646)]

sqlalchemy注意点

1. filter_by(name='haha').count()的坑

# 执行上述的count方式:
temp_count = dbm.PersonnelBlacklist.query.filter(text(sql_text)).params(**sql_params).count()

# sqlalchemy执行的sql为:
 """转化sql含义为先搜索出所有sql对象,在统计所有数据对象的数量,当数据量大的时候,这样会严重影响速度。"""
SELECT count(*) AS count_1 
FROM (SELECT * FROM account_personnel_blacklist) AS anon_1


# 优化方式:
temp_count = db.session.query(func.count(dbm.PersonnelBlacklist.id)).\
            filter(text(sql_text)).params(**sql_params).first()[0]
# 这样转化过来的sql为:
# 直接执行搜索数量,数据量大的时候,提升回很明显
SELECT count(account_personnel_blacklist.id) AS count_1 
FROM account_personnel_blacklist  LIMIT %(param_1)s

2.pagination_obj.items和pagination_obj.total的弊端

  • 得到pagination的分页对象后<flask_sqlalchemy.Pagination object at 0x7fd7046df9d0>,内部有items用于获取所有对象,total获取总的数量(筛选条件下,不做分页)

  • 虽然得到的是一个对象,但想获取到数据和总数量,这里会隐式的执行两条sql(一条用于查数据,一条用于查总数量)

  • 如下的两条(与上边count的坑一致):

    • select * from account
    • select count(*) from account (select * from account) as temp_data
  • 但但是上边的操作,对coder比较友好,一行代码即可搞定。若要优化好可以将获取数据,获取总数量(select count(id) from account)分成两步精简的sql进行执行

(venv) gapinyc@DESKTOP-9QS7RL5:~/superset$ pip install --upgrade pymysql sqlalchemy flask-sqlalchemy Looking in indexes: https://pypi.tuna.tsinghua.edu.cn/simple/ Requirement already satisfied: pymysql in ./venv/lib/python3.10/site-packages (1.1.2) Requirement already satisfied: sqlalchemy in ./venv/lib/python3.10/site-packages (1.4.54) Collecting sqlalchemy Downloading https://pypi.tuna.tsinghua.edu.cn/packages/4a/d8/c63d8adb6a7edaf8dcb6f75a2b1e9f8577960a1e489606859c4d73e7d32b/sqlalchemy-2.0.44-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl (3.2 MB) ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 3.2/3.2 MB 11.5 MB/s 0:00:00 Requirement already satisfied: flask-sqlalchemy in ./venv/lib/python3.10/site-packages (2.5.1) Collecting flask-sqlalchemy Downloading https://pypi.tuna.tsinghua.edu.cn/packages/1d/6a/89963a5c6ecf166e8be29e0d1bf6806051ee8fe6c82e232842e3aeac9204/flask_sqlalchemy-3.1.1-py3-none-any.whl (25 kB) Requirement already satisfied: greenlet>=1 in ./venv/lib/python3.10/site-packages (from sqlalchemy) (3.1.1) Requirement already satisfied: typing-extensions>=4.6.0 in ./venv/lib/python3.10/site-packages (from sqlalchemy) (4.15.0) Requirement already satisfied: flask>=2.2.5 in ./venv/lib/python3.10/site-packages (from flask-sqlalchemy) (2.3.3) Requirement already satisfied: Werkzeug>=2.3.7 in ./venv/lib/python3.10/site-packages (from flask>=2.2.5->flask-sqlalchemy) (3.1.3) Requirement already satisfied: Jinja2>=3.1.2 in ./venv/lib/python3.10/site-packages (from flask>=2.2.5->flask-sqlalchemy) (3.1.6) Requirement already satisfied: itsdangerous>=2.1.2 in ./venv/lib/python3.10/site-packages (from flask>=2.2.5->flask-sqlalchemy) (2.2.0) Requirement already satisfied: click>=8.1.3 in ./venv/lib/python3.10/site-packages (from flask>=2.2.5->flask-sqlalchemy) (8.3.0) Requirement already satisfied: blinker>=1.6.2 in ./venv/lib/python3.10/site-packages (from flask>=2.2.5->flask-sqlalchemy) (1.9.0) Requirement already satisfied: MarkupSafe>=2.0 in ./venv/lib/python3.10/site-packages (from Jinja2>=3.1.2->flask>=2.2.5->flask-sqlalchemy) (3.0.3) Installing collected packages: sqlalchemy, flask-sqlalchemy Attempting uninstall: sqlalchemy Found existing installation: SQLAlchemy 1.4.54 Uninstalling SQLAlchemy-1.4.54: Successfully uninstalled SQLAlchemy-1.4.54 Attempting uninstall: flask-sqlalchemy Found existing installation: Flask-SQLAlchemy 2.5.1 Uninstalling Flask-SQLAlchemy-2.5.1: Successfully uninstalled Flask-SQLAlchemy-2.5.1 ERROR: pip's dependency resolver does not currently take into account all the packages that are installed. This behaviour is the source of the following dependency conflicts. flask-appbuilder 4.8.1 requires Flask-SQLAlchemy<3,>=2.4, but you have flask-sqlalchemy 3.1.1 which is incompatible. flask-appbuilder 4.8.1 requires SQLAlchemy<1.5, but you have sqlalchemy 2.0.44 which is incompatible. apache-superset 5.0.0 requires sqlalchemy<2,>=1.4, but you have sqlalchemy 2.0.44 which is incompatible. Successfully installed flask-sqlalchemy-3.1.1 sqlalchemy-2.0.44 (venv) gapinyc@DESKTOP-9QS7RL5:~/superset$
最新发布
10-26
你执行了: ```bash pip install --upgrade pymysql sqlalchemy flask-sqlalchemy ``` 结果 **升级到了 SQLAlchemy 2.0.44 和 Flask-SQLAlchemy 3.1.1**,但出现了关键的兼容性错误: ``` ERROR: pip's dependency resolver does not currently take into account all the packages that are installed. This behaviour is the source of the following dependency conflicts. flask-appbuilder 4.8.1 requires Flask-SQLAlchemy<3,>=2.4, but you have flask-sqlalchemy 3.1.1 which is incompatible. flask-appbuilder 4.8.1 requires SQLAlchemy<1.5, but you have sqlalchemy 2.0.44 which is incompatible. apache-superset 5.0.0 requires sqlalchemy<2,>=1.4, but you have sqlalchemy 2.0.44 which is incompatible. ``` --- ## ⚠️ 问题严重性 你已经破坏了 Superset 的依赖环境! ### ❌ 当前状态: - `SQLAlchemy=2.0.44` → 不被 FAB 和 Superset 支持 - `Flask-SQLAlchemy=3.1.1` → 要求 SQLAlchemy ≥2.0,但 Superset 只支持 <2 - **后果:Superset 将无法正常运行,API 报错、数据库连接失败、ORM 映射崩溃** > ✅ **结论:必须回滚到兼容版本!** --- ## ✅ 正确解决方案:降级 SQLAlchemy 和 Flask-SQLAlchemy Apache Superset **5.0.0** 和 Flask AppBuilder **4.8.1** 对 SQLAlchemy 有严格限制: | 包 | 兼容版本范围 | |----|-------------| | `SQLAlchemy` | `<2.0`, `>=1.4` → 推荐 `1.4.54` | | `Flask-SQLAlchemy` | `<3.0`, `>=2.4` → 推荐 `2.5.1` | ### 🔧 修复命令(立即执行) ```bash pip install "SQLAlchemy==1.4.54" "Flask-SQLAlchemy==2.5.1" ``` 📌 输出应类似: ``` Installing collected packages: SQLAlchemy, Flask-SQLAlchemy Attempting uninstall: SQLAlchemy Removing file: /home/gapinyc/superset/venv/lib/python3.10/site-packages/SQLAlchemy-2.0.44.dist-info Successfully uninstalled SQLAlchemy-2.0.44 Attempting uninstall: Flask-SQLAlchemy Removing file: /home/gapinyc/superset/venv/lib/python3.10/site-packages/Flask_Sqlalchemy-3.1.1.dist-info Successfully uninstalled Flask-SQLAlchemy-3.1.1 Successfully installed SQLAlchemy-1.4.54 Flask-SQLAlchemy-2.5.1 ``` ✅ 验证是否安装成功: ```bash python -c "import sqlalchemy; print(sqlalchemy.__version__)" # 输出:1.4.54 python -c "import flask_sqlalchemy; print(flask_sqlalchemy.__version__)" # 输出:2.5.1 ``` --- ## 🛠️ 补充配置建议 ### 1. 在 `superset_config.py` 中启用连接池健康检查 虽然不能用 `pool_pre_ping=True`(它在 SQLAlchemy 1.4 中可用),但你应该加上: ```python # superset_config.py import os SECRET_KEY = '1sCjCsfAPMBskPWPSJ0Gja7JvpufVc50vTW04MSiJuzNN3JPlUYL3MR+' # 示例 MySQL 连接(替换为你的) SQLALCHEMY_DATABASE_URI = 'mysql+pymysql://user:password@localhost/superset_db?charset=utf8mb4' # 关键:防止 “Command Out of Sync” 和 “Lost connection” SQLALCHEMY_ENGINE_OPTIONS = { "pool_pre_ping": True, # ✅ 在 SQLAlchemy 1.4 中已支持 "pool_recycle": 3600, # 每小时重建连接,避免 MySQL 超时断开 "pool_timeout": 30, "max_overflow": 10, "connect_args": {"connect_timeout": 10}, } ``` > ✅ `pool_pre_ping=True` 是解决 `OperationalError (2013/2014)` 的最有效方式,即使在 SQLAlchemy 1.4 中也完全支持。 --- ### 2. 确保其他依赖版本正确 推荐锁定以下版本(适用于 Superset 5.0): ```txt # requirements.txt apache-superset==5.0.0 PyMySQL==1.1.2 SQLAlchemy==1.4.54 Flask-SQLAlchemy==2.5.1 flask-appbuilder==4.8.1 ``` 安装命令: ```bash pip install -r requirements.txt ``` --- ## ✅ 后续操作流程 ### Step 1:确认数据库 URI 正确 确保你在 `superset_config.py` 或 `.env` 中设置了正确的元数据库地址: ```python SQLALCHEMY_DATABASE_URI = 'mysql+pymysql://superset:your_password@localhost/superset?charset=utf8mb4' ``` > 💡 建议不要使用 SQLite,生产环境推荐 MySQL 或 PostgreSQL。 --- ### Step 2:运行数据库迁移 ```bash superset db upgrade ``` 这会创建或更新所有必要的表(包括 `ab_role`, `ab_permission_view` 等)。 --- ### Step 3:初始化权限系统 ```bash superset init ``` 输出示例: ``` Recognized Database Authentications. Creating default roles and permissions Admin user admin created Inserting roles as bulk insert is more efficient Creating default roles ... Done ``` --- ### Step 4:重启 Gunicorn ```bash gunicorn \ --bind 0.0.0.0:8088 \ --workers 4 \ --worker-class gthread \ --threads 4 \ --timeout 120 \ --max-requests 1000 \ --max-requests-jitter 100 \ --preload \ --access-logfile - \ --error-logfile - \ "superset.app:create_app()" ``` 刷新页面后,之前的 500 错误应该消失。 --- ## 🧰 如何避免未来出现此类问题? ### ✅ 方法 1:使用虚拟环境 + 固定版本 ```bash python -m venv venv source venv/bin/activate pip install apache-superset==5.0.0 pip freeze > requirements.txt # 锁定当前工作版本 ``` 以后部署都用: ```bash pip install -r requirements.txt ``` ### ✅ 方法 2:不要随意升级包 除非明确知道新版本兼容,否则不要执行: ```bash pip install --upgrade xxx ``` 特别是 `SQLAlchemy`, `Flask`, `Werkzeug` 这类核心库。 --- ## 🔍 总结 | 问题 | 解决方案 | |------|----------| | `NoSuchColumnError` / `Command Out of Sync` | 降级 SQLAlchemy1.4.x 并启用 `pool_pre_ping` | | `flask-appbuilder` 依赖冲突 | 安装 `Flask-SQLAlchemy==2.5.1` | | 权限系统异常 | 执行 `superset db upgrade && superset init` | | 数据库连接中断 | 使用 `pool_pre_ping=True` + `pool_recycle=3600` | ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值