前言
说起事务,后端工程师都不会陌生,这是存在于关系型数据库中的一个特性,它具有四个特性:
原子性
事务包含的所有操作要么都执行成功,要么都失败,不可分割
一致性
中间过程不管怎么执行,结果一定是一致的
隔离性
事务在执行过程中,不受其他事务的影响
持久性
执行成功之后,结果时永久修改的,不能撤回
MySQL执行的SQL是autocommit的,SALAlchemy 查询语句也是 autocommit的,就是说如果没有明确声明事务的begin,每个单独的SQL都是一个独立的事务。但是在做交易系统时,比如银行给用户A转账给用户B时,有两个操作,从A里面减100,然后给B加100。这两个操作必须放在一个事务里面才行,否是就会出现钱扣了,对方又没到账的情况。
所以,事务,是sqlalchemy乃至所有orm不可或缺的一环
开启事务
开启事务有两种方法,这里只说最简单的一种方法,就是利用with,为了更加真实的模拟业务场景,我们创建两张表和sqlalchemy的连接
from sqlalchemy import create_engine, Column, Integer, String
from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy.orm import sessionmaker
connect = create_engine('mysql+pymysql://root:root@localhost:3306/test01')
ModelBase = declarative_base()
class User(ModelBase):
# 定义表名
__tablename__ = "user"
# 声明字段
id = Column(Integer, primary_key=True)
name = Column(String(length=255))
class Role(ModelBase):
__tablename__ = 'role'
id = Column(Integer, primary_key=True)
role = Column(String(length=255))
DBSession = sessionmaker(bind=connect,autoflush=False, autocommit=False, expire_on_commit=True)
然后我们利用一个fastapi框架来模拟一下
from fastapi import FastAPI, HTTPException, status
app = FastAPI()
@app.get('/')
async def create_sqlalchemy():
# 使用上下文管理器开启事务
with DBSession.begin() as session:
data = {
"id": 0,
'name': 'Salmon'
}
# 添加user数据
new_user = User(**data)
session.add(new_user)
data2 = {
'id': 0,
# 'id':'添加错误数据'
'role':'SuperUser1'
}
# 添加role数据
new_role = Role(**data2)
session.add(new_role)
# 模拟错误
if data2['role'] == 'SuperUser1':
raise HTTPException(status_code=status.HTTP_400_BAD_REQUEST)
return 'ok'
需要知道的是,在事务开启后,使用with不需要自己来执行commit操作,执行完sql会自动提交,如果报异常会自动rollback 。
我们这里,主动抛出异常,两个表中的数据都没有改变。然后我们发送一个错误数据,不主动抛出,再来试试,解开那个id注释。然后把if和raise这两行删掉,然后,引发他原生错误。数据也不会发生改变。
- Post link: https://www.godhearing.cn/sqlalchemy-de-shi-wu/
- Copyright Notice: All articles in this blog are licensed under unless otherwise stated.