表被锁解决方法
# 列出当前进程
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()
验证
- 观察表记录, 未发生多次写入问题
- 新开一个python, 使用协程插入数据
worker: 10
loop: 20
执行完毕后查看是否有多余的等待进程
show processlist;
只有一条当前查询的记录, 结果未见异常
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()
验证
- 观察表记录, 未发生多次写入问题
- 新开一个python, 使用协程插入数据
worker: 10
loop: 20
执行完毕后查看是否有多余的等待进程
show processlist;
可以看到有4个进程处于sleep状态, 重启flask并不能正常结束, 只能手动kill掉
4 条评论
最后一个demo两把不同的锁有几率造成死锁
应该是这个问题,并发执行了看着像。有啥好的解决思路么?
缩进有点问题吧(if 代码段的缩进不是4),然后你那个“存在问题的用法”的代码
```python
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()
db.session.commit() # 提交事务不该放在 if 下面吧,不然会存在不被执行的情况
```
缩进确实有问题,已经调整过来了。提交事务这个放在if下面是没问题的,因为整个事务都在if里,要么全执行 要么全不执行。