sqlalchemy行锁总结 & 解锁方法

表被锁解决方法

# 列出当前进程
show processlist;

# 结束进程
kill 进程id

行锁基本使用

# 插入数据前先判断表中是否存在记录, 查询时加锁
if not Model.query.filter_by(column=value).with_for_update():
    obj = Model(
        column=value
    )    
    db.session.add(obj)
    # 提交事务, 锁解除
    db.session.commit()

行锁连续使用

# 插入数据前先判断表中是否存在记录, 查询时加锁
if not ClientUserinfo.query.filter_by(fingerprint=project_token).with_for_update().scalar():
    obj = ClientUserinfo(
        JSfingerprint=project_name,
        fingerprint=project_token,
        install_time=get_now(),
        last_updatetime=get_now(),
        ver=ver,
        warn_status=0,
        notify_time="09:00",
        username=username
    )
    db.session.add(obj)
    # 提交事务, 锁解除
    db.session.commit()

    # 初始化开关控制allowed表
    allowed_obj = MirrorApiAllowed.query.filter_by(name=project_name).with_for_update()
    if not allowed_obj.scalar():
      allowed_obj = MirrorApiAllowed(
          name=project_name,
          config=json.dumps({'all': '1'}),
          update_time=get_now()
      )
      db.session.add(allowed_obj)
      db.session.commit()

验证

  1. 观察表记录, 未发生多次写入问题
  2. 新开一个python, 使用协程插入数据

worker: 10
loop: 20
执行完毕后查看是否有多余的等待进程

show processlist;

image.png
只有一条当前查询的记录, 结果未见异常
PS: 如果是用python协程requests调用远程接口(如flask写的api)写入数据, 可能会存在worker数量的查询记录, 这是正常的, 猜测是因为链接没断开导致的, 只需要reload一下flask, 记录就会正常删除

存在问题的用法

以下代码在验证时发现有多个卡在sleep状态的进程, 猜测是因为并发行锁导致的, 具体原理不明, 先码下来
虽然存在卡进程的情况, 但并未发生多次写入的问题

# 插入数据前先判断表中是否存在记录, 查询时加锁
if not ClientUserinfo.query.filter_by(fingerprint=project_token).with_for_update().scalar():
    # 判断另一个表中是否存在记录, 查询时加锁
    # 这里存在问题, 上个锁还未提交, 又加了一次锁
    allowed_obj = MirrorApiAllowed.query.filter_by(name=project_name).with_for_update()
    if not allowed_obj.scalar():
      allowed_obj = MirrorApiAllowed(
          name=project_name,
          config=json.dumps({'all': '1'}),
          update_time=get_now()
      )
      db.session.add(allowed_obj)
      # 提交事务, 锁解除
      # 也可能是这一步引发的下面的问题?
      db.session.commit()
    obj = ClientUserinfo(
        JSfingerprint=project_name,
        fingerprint=project_token,
        install_time=get_now(),
        last_updatetime=get_now(),
        ver=ver,
        warn_status=0,
        notify_time="09:00",
        username=username
    )
    db.session.add(obj)
    # 提交事务, 锁解除
    db.session.commit()

验证

  1. 观察表记录, 未发生多次写入问题
  2. 新开一个python, 使用协程插入数据

worker: 10
loop: 20
执行完毕后查看是否有多余的等待进程

show processlist;

image.png
可以看到有4个进程处于sleep状态, 重启flask并不能正常结束, 只能手动kill掉

本文链接:

https://www.lzskyline.com/archives/106/
1 + 5 =
快来做第一个评论的人吧~