本文用于记录在使用MySQL的过程中遇到的坑,持续更新。
1.主从数据库数据不一致
转后端后的第一个项目正式上线了,运营刚使用就接连发现两个bug,尴尬到脚趾抠穿地板...
其实这两个bug产生的原因都是一个:主从数据库中的数据不一致。测试环境的数据库没有配置读写分离,所以没有测出bug,正式环境一用上就发现问题了。
写数据是在主数据库中,读数据是在从数据库中,当主数据库的数据还没有同步到从数据库中的时候,读取的数据不是最新的。
两个bug出现的场景都一样,在一个事务中进行了更新创建等操作,在事务外取数据,简化如下:
with transaction.atomic():
model_one = ModelOne.objects.get(pk=model_one_id)
... # 在这个事务中对多个表进行了创建/读取/更新处理
model_one.a = 'a_new_value'
model_one.save()
model_two = ModelTwo.objects.create(**model_two_data)
model_two_id = model_two.id
...
model_one = ModelOne.objects.get(pk=model_one_id)
function_a(model_one.a) # 在主从数据库数据库未同步的时候取到的是旧值
model_two = ModelTwo.objects.get(pk=model_two_id) # 在主从数据库数据库未同步的时候没有这条数据,会报错
function_b(model_two)
根据MySQL主从复制读写分离这篇文章所说:
同一个线程且同一数据库连接内,如有写入操作,以后的读操作均从主库读取
事务中的处理在同一线程,所以解决方案是,在事务中把数据整理好,放到一个变量中,直接使用那个变量:
model_one_a = None
model_two = None
with transaction.atomic():
# 1
model_one = ModelOne.objects.get(pk=model_one_id)
... # 在这个事务中对多个表进行了创建/读取/更新处理
model_one.a = 'a_new_value'
model_one.save()
model_one_a = 'a_new_value'
# 2
model_two = ModelTwo.objects.create(**model_two_data)
...
# 3
data_for_update = {
'a': '1',
'b': 2,
...
}
ModelThree.objects.filter(pk=model_three_id).update(**data_for_update)
model_three = ModelThree.objects.get(pk=model_three_id)
...
...
function_a(model_one_a) # 1.使用准备好的变量model_one_a
function_b(model_two) # 2.不重新使用get从数据库取值了,直接使用model_two变量
functuin_c(model_three) # 3.在事务中已经获取了该数据并放到了变量model_three中