Skip to content

AOP 事务管理 ​

项目采用 AOP(面向切面编程)风格的事务管理机制,通过中间件自动管理数据库事务,业务代码无需手动调用 commit 或 rollback。

设计理念 ​

传统的事务管理方式需要在业务代码中显式调用 commit 和 rollback,这种方式存在以下问题:

  1. 代码侵入性强:业务代码需要关注事务细节
  2. 容易遗漏:忘记调用 rollback 可能导致数据不一致
  3. 重复代码:每个写操作都需要相同的事务处理逻辑

AOP 事务管理通过中间件自动处理事务,业务代码只需关注业务逻辑。

实现原理 ​

事务管理通过 src/middleware/transaction.py 实现:

python
from flask import request, g
from src.core.database import db

def register_transaction(app):
    """注册 AOP 事务管理中间件"""

    @app.before_request
    def _transaction_begin():
        """请求开始前:标记事务活跃"""
        g.transaction_active = True

    @app.after_request
    def _transaction_commit(response):
        """请求结束后:根据响应状态决定提交或回滚"""
        if request.method in ('POST', 'PUT', 'DELETE', 'PATCH'):
            if response.status_code == 200:
                try:
                    body = response.get_json()
                    if body and body.get('code') == 0:
                        # 业务成功:提交事务
                        db.session.commit()
                    else:
                        # 业务失败:回滚事务
                        db.session.rollback()
                except Exception:
                    db.session.rollback()
            else:
                # HTTP 非 200:回滚事务
                db.session.rollback()
        return response

    @app.teardown_request
    def _transaction_rollback(exception):
        """请求异常时:回滚事务"""
        if exception:
            db.session.rollback()
        # 移除会话
        db.session.remove()

事务触发规则 ​

HTTP 方法响应状态业务 code事务操作
POST2000(成功)commit
POST2001(失败)rollback
PUT2000(成功)commit
PUT2001(失败)rollback
DELETE2000(成功)commit
DELETE2001(失败)rollback
PATCH2000(成功)commit
PATCH2001(失败)rollback
GET任意任意不处理(只读)
任意非 200任意rollback
任意异常任意rollback

业务代码示例 ​

标准 CRUD 操作 ​

python
from src.modules.system.position.models import Position

def add_position(data):
    """新增岗位"""
    # 创建模型实例
    position = Position()
    position.name = data['name']
    position.status = data['status']
    position.sort = data['sort']

    # 保存到数据库(仅 flush,不 commit)
    position.save()

    # 返回成功响应
    return R.ok(msg="新增成功")

批量操作 ​

python
def delete_positions(id_list):
    """批量删除岗位"""
    # 批量软删除(仅 flush,不 commit)
    PositionRepository.batch_delete(id_list)

    # 返回成功响应
    return R.ok(msg="删除成功")

多表操作 ​

python
def transfer_user(user_id, new_dept_id):
    """转移用户部门"""
    # 更新用户部门
    user = UserRepository.get_by_id(user_id)
    user.dept_id = new_dept_id
    user.save()

    # 更新部门人数统计
    dept = DeptRepository.get_by_id(new_dept_id)
    dept.user_count = DeptRepository.count_users(new_dept_id)
    dept.save()

    # 两个操作在同一个事务中,要么都成功,要么都回滚
    return R.ok(msg="转移成功")

BaseDB.save() 方法 ​

BaseDB 基类提供的 save() 方法只执行 flush,不执行 commit:

python
class BaseDB:
    def save(self):
        """保存模型到数据库(仅 flush,不 commit)"""
        db.session.add(self)
        db.session.flush()
        return self

flush 的作用:

  1. 将 SQL 语句发送到数据库执行
  2. 获取自增 ID 等数据库生成的值
  3. 但不提交事务,事务由中间件统一管理

特殊情况处理 ​

需要立即提交的场景 ​

某些特殊场景需要立即提交事务,可以使用 TransactionContext 上下文管理器:

python
from src.middleware.transaction import TransactionContext

def import_data(file):
    """导入数据(需要立即提交)"""
    with TransactionContext():
        # 在此上下文中的操作会立即提交
        for row in parse_excel(file):
            position = Position(**row)
            position.save()

    # 上下文结束后自动提交
    return R.ok(msg="导入成功")

需要手动回滚的场景 ​

某些业务场景需要手动回滚:

python
from src.core.database import db

def complex_operation():
    """复杂操作(需要手动回滚)"""
    try:
        # 执行一系列操作
        user = User(...)
        user.save()

        # 检查业务条件
        if not check_condition(user):
            # 手动回滚
            db.session.rollback()
            return R.failed("条件不满足")

        # 继续其他操作
        # ...

        return R.ok(msg="操作成功")
    except Exception as e:
        # 异常时手动回滚
        db.session.rollback()
        raise

注意事项 ​

重要提示

  1. 不要手动调用 db.session.commit():事务由中间件统一管理,手动 commit 可能导致事务提前提交
  2. 不要手动调用 db.session.rollback():除非在 try-except 块中需要手动回滚
  3. 只读操作使用 GET 方法:GET 请求不会触发事务处理
  4. 写操作必须返回 R 对象:中间件通过 code 字段判断是否需要提交

总结 ​

AOP 事务管理通过中间件自动处理数据库事务,业务代码无需手动调用 commit 或 rollback。save() 方法只执行 flush,事务由中间件在请求结束时统一提交或回滚。这种设计简化了业务代码,提高了代码可维护性,同时保证了数据一致性。

小蚂蚁云团队 · 提供技术支持