Flask-Sqlalchemy 事务

数据库事务

数据库事务( transaction)是访问并可能操作各种数据项的一个数据库操作序列,这些操作要么全部执行,要么全部不执行,是一个不可分割的工作单位。例如,在新增数据A后更新数据B,当更新数据B失败后,要回滚数据库,使得数据A不能新增到数据库中,这就是数据的原子性。

  • 原子性(Atomicity):事务中的全部操作在数据库中是不可分割的,要么全部完成,要么全部不执行。
  • 一致性(Consistency):几个并行执行的事务,其执行结果必须与按某一顺序 串行执行的结果相一致。
  • 夺隔离性(Isolation):事务的执行不受其他事务的干扰,事务执行的中间结果对其他事务必须是透明的。
  • 夺持久性(Durability):对于任意已提交事务,系统必须保证该事务对数据库的改变不被丢失,即使数据库出现故障。

Flask-Sqlalchemy中的事务

在flask中,如果要想保证事务的原子性应该如何操作呢?
看下面这个例子:

业务逻辑
新增分组并保存分组与用户的关联关系。在分组表中新增一个分组并获取到分组id,然后在关联表中循环插入分组与用户的关联关系。
数据库表结构
数据库中有一个分组表(case_group)和分组权限表(user_auth),分组权限表中保存组id和用户id来关联用户和分组,用户和分组是多对多的关系。此处省略用户表。

CREATE TABLE `case_group` (
  `create_time` datetime DEFAULT NULL,
  `update_time` datetime DEFAULT NULL,
  `delete_time` datetime DEFAULT NULL,
  `id` int(11) NOT NULL AUTO_INCREMENT COMMENT '分组id',
  `name` varchar(20) DEFAULT NULL COMMENT '分组名称 全局唯一不可重复',
  `info` varchar(50) DEFAULT NULL COMMENT '分组描述',
  PRIMARY KEY (`id`),
  UNIQUE KEY `name` (`name`)
) ENGINE=InnoDB AUTO_INCREMENT=7 DEFAULT CHARSET=utf8mb4;

CREATE TABLE `user_auth` (
  `create_time` datetime DEFAULT NULL,
  `update_time` datetime DEFAULT NULL,
  `delete_time` datetime DEFAULT NULL,
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `user_id` int(11) NOT NULL COMMENT '用户id',
  `auth_id` int(11) NOT NULL COMMENT '权限id',
  `type` smallint(6) NOT NULL COMMENT '权限id类型 ;  1 -> group分组 |  2 -> project工程',
  PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=13 DEFAULT CHARSET=utf8mb4;

模型中操作数据库的方法

    @classmethod
    def new_group(cls, form):
        group = CaseGroup.query.filter_by(name=form.name.data, delete_time=None).first()
        if group is not None:
            raise ParameterException(msg='分组已存在')
        # 新增分组的时候同时新增可查看当前用例组的人员。当出现问题时进行回滚,人员和分组都不插入
        try:
            group = CaseGroup()
            group.name = form.name.data
            group.info = form.info.data
            db.session.add(group)
            db.session.flush()
            if form.users.data:
                current_app.logger.info(group.id)
                for user in form.users.data:
                    user_auth = UserAuth()
                    user_auth.user_id = user
                    user_auth.auth_id = group.id
                    user_auth.type = UserAuthEnum.GROUP
                    db.session.add(user_auth)
            db.session.commit()
        except Exception as e:
            db.session.rollback()
            raise UnknownException(msg='新增异常 数据已回滚')

        return True

用try except 将2次新增操作包裹起来,当出现异常时使用db.session.rollback()进行数据回滚。
在一次新增后使用db.session.add()进行数据暂存,此时并未真正提交到数据库中,需要在所有操作执行后执行db.session.commit()进行数据提交。
在这个例子中,新增关联表的数据需要已新增分组数据的id,此时未commit所以自增id为None,需要在新增分组后使用db.session.flush()刷新获取分组id。

你可能感兴趣的:(点点点工程师)