python - 并发进程中的 Django select_for_update 函数
问题描述
当我update_or_create
在多线程条件下测试功能时,我发现结果不是我想要的,他们在 MySQL 中创建了多个记录。如代码所示,update_or_create
用于select .. for update
锁定 MySQL 中的行,那么它在 MySQL 中应该只有一条记录。我用 SQLAlchemy 和行 sql 证明了这一点。
那么,Django 代码错了吗?
使用 Django 代码:
def get_or_create_ins():
p, created = OxalicAcid.objects.update_or_create(defaults={"formula": "20", "degree": "80"}, name="smart")
def run():
for i in range(10):
t = threading.Thread(target=get_or_create_ins, args=())
t.start()
if __name__ == "__main__":
# more than one record will be created
run()
使用 SQLAlchemy 代码:
@contextmanager
def transaction_atomic():
session = Session()
try:
yield session
session.commit()
except Exception as e:
session.rollback()
raise e
def get_result_with_update(session, name):
sql = text("""
select * from acid_oxalicacid where name = :name for update
""")
params = dict(name=name)
cursor = session.execute(sql, params)
result = cursor.fetchall()
return result
def get_result(session, name):
sql = text("""
select * from acid_oxalicacid where name = :name
""")
params = dict(name=name)
cursor = session.execute(sql, params)
result = cursor.fetchall()
return result
def create_data(session, name, degree, formula):
sql = text("""
insert into acid_oxalicacid (name, degree, formula) values (:name, :degree, :formula)
""")
params = dict(
name=name,
degree=degree,
formula=formula
)
session.execute(sql, params)
def get_or_create():
name = "smart"
degree = "50"
formula = "100"
with transaction_atomic() as session:
res = get_result_with_update(session, name)
if not res:
create_data(session, name, degree, formula)
res = get_result(session, name)
return res
if __name__ == "__main__":
# Only one record be created, that's correct
for i in range(10):
t = threading.Thread(target=get_or_create, args=())
t.start()
解决方案
因为django使用'read committed'事务隔离级别,所以会是多条记录,如果改成'repeatable read',在数据库中就只有一条记录了。
推荐阅读
- python - 将 XML 转换为用于 BigQuery 的 JSON 可加载结构
- swiftui - 如何将@published 和@observed 与FSCalendar 一起使用?
- regex - 在 perl 中搜索和替换特殊字符
- c# - 如何在 UWP 应用程序中添加使用 inkCanvas 和 Canvas 缩放网格?
- graphql-js - Relay Modern BadRequestError:缺少多部分字段“操作”
- python - Pyaudio 没有找到,也无法安装。我的虚拟助手需要它
- vue.js - 使与 VUEJS 中的数据匹配的选项中的文本加粗
- c# - 使用 OneDrive SDK 上传大文件时如何提高速度
- c# - 如何从字符串中按名称选择对象
- unity3d - Unity AR Foundation AR Tracked Image Manager 出现黑屏