出门旅行前总要订票、订酒店,这一连串操作就像程序里的多个ref="/tag/426/" style="color:#E3A3CF;font-weight:bold;">数据库动作,要么全部成功,要么全都不算数。比如你买高铁票时,扣钱和出票得一起完成,要是只扣了钱却没出票,那可就麻烦了。在开发中,这种“成则全成,败则全败”的机制靠的就是事务处理。
什么是ORM中的事务
ORM(对象关系映射)让我们用代码操作数据库时不用写太多SQL。而事务是保证一组操作原子性的手段。举个例子,用户下单旅游套餐,要同时扣除余额、生成订单、锁定库存,这三步必须一起成功,否则就得回滚,不能留下半拉子工程。
Django中的事务用法
Django的ORM提供了简洁的事务控制方式。常用的是transaction.atomic装饰器或上下文管理器。它能确保代码块内的数据库操作处于同一个事务中。
from django.db import transaction
# 用作装饰器
@transaction.atomic
def create_booking():
Order.objects.create(user_id=1, amount=599)
Inventory.objects.filter(id=10).update(available=False)
# 或者用上下文管理器
def process_payment():
with transaction.atomic():
Account.objects.filter(user=1).update(balance=F('balance') - 200)
TransactionLog.objects.create(user=1, amount=200)
只要其中任意一步出错,整个操作都会自动回滚,不会留下脏数据。
SQLAlchemy的事务控制
在使用SQLAlchemy这类ORM工具时,会通过session来管理事务。默认情况下,每次提交都需要手动调用commit,异常时可以rollback。
from sqlalchemy.orm import sessionmaker
Session = sessionmaker(bind=engine)
session = Session()
try:
user = User(name="jack")
session.add(user)
session.commit() # 提交事务
except:
session.rollback() # 出错回滚
finally:
session.close()
也可以用上下文管理器简化流程,避免忘记关闭或回滚。
嵌套事务与保存点
有时候一个大事务里还有小步骤,比如预订行程时先锁酒店再锁车票。Django支持保存点,允许部分回滚而不影响整体。
with transaction.atomic():
Order.objects.create(status="created")
try:
with transaction.atomic():
HotelBooking.reserve(room_id=5)
raise Exception("预订失败") # 这里会回滚酒店预订
except Exception:
print("酒店预订取消,但主订单仍存在")
CarRental.reserve(vehicle_id=3) # 继续执行租车
这样的结构让复杂业务逻辑更灵活,出错也能精准控制范围。
事务隔离带来的实际问题
多人同时抢特价机票时,可能出现超卖。这是因为事务隔离级别设置不当。数据库默认的READ COMMITTED能防止读未提交数据,但要避免重复预订还得加锁或使用SELECT FOR UPDATE。
with transaction.atomic():
# 加锁查询,防止并发修改
room = Room.objects.select_for_update().get(id=10)
if room.available:
room.book()
这样在同一事务中锁定记录,其他请求就得排队,确保不会重复分配资源。
无论是订票还是管理系统,事务都是保障数据一致的核心。ORM提供的这些工具,让开发者能像规划一次完美旅程一样,把每一步安排得稳妥可靠。