MySQL 踩坑记录

289 阅读2分钟

本文用于记录在使用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中