文章编写背景
实际项目中,因配置的变动,遇到了事务不生效的场景
执行环境:循环操作,同时修改多数据库,有原子性要求。
常规事务使用
from A import goods
from django.db import transaction
with transaction.atomic():
# your code
这是常规,单数据库的事务使用。如果是多数据库,且用到了Django的库路由时,上面的方法就会存在不生效了。
Django 数据库路由:
DATABASES = {
"default":{},
"DB_A":{},
"DB_B":{}
}
DATABASE_APPS_MAPPING = {
"DB_A":"A",
"DB_B":"B"
}
假设我们依然这么写:
from A import goods
from B import orders
from django.db import transaction
# 假设goods是数据库A,orders是数据库B
with transaction.atomic():
# your code
g = goods.xxxx.objects.filter().update()
o = orders.xxxx.objects.filter().update()
那么此时事务生效的,只是django 配置文件中是default的数据库才会生效。其他路由的数据库中的事务操作是不生效的。
本文实际场景:
原 goods 与orders是同一个库,且django配置文件中也只有default。即是只有一个数据库。随着业务量数据量的增长,单库性能问题,这时候就把其中核心业务表拆离出来。此时之前的事务代码就失效了。
生效示例:
from A import goods
from B import orders
with transaction.atomic(using="DB_A"):
with transaction.atomic("DB_B"):
for g in goods_filtter:
pass
这里原来不指定using参数,默认值为using=“default”
只要循环中有一步出错了,那么整个事务就会回滚,且里面的两个库的操作都会回滚。这里DB_A 和DB_B的顺序根据实际场景来确定。
总结
很多基础不扎实的朋友,遇到事务操作都会直接去搜【django 中使用事务】,然后搜到的都是千篇一律的 with transaction.atomic():的常规使用,遇到特殊场景就不生效了。
谨此记录现实遇到的小问题~