最近开发中遇到个小问题,因为业务上的设计存在问题,导致数据库表总是被锁,而且是不定期的锁定,导致服务器运行异样,最初通过排查起因是多线程同时更新同一表中同一条记录导致问题。明天就来跟大家说说该如何防止这种问题。
问题形容
最近因为公司业务须要,产品设计了一套业务零碎,据说会有很多外部和内部人员应用,拿到零碎阐明咱们研发部门拼命加班赶时间,经验了两个月的后终于把零碎上线运行。
刚开始用的人少,并没有呈现什么问题,感觉零碎还是很稳固,随着起初用的人越来越多,零碎就开始呈现一些莫名其妙的问题,其中就有某些业务信息在更新的时候总是报错,查日志就发现是表记录被锁定导致更新失败。
找到谬误问题后咱们就开始一遍遍的翻日志,各种剖析查找到底是什么起因导致了表记录被锁。最初发现这个表的状态字段,存在多个接口办法同时更新的状况,而且常常是同时操作的。也就是数据库中存在多个会话同时操作同一表中同一行记录,从而导致表记录被锁。
问题剖析
那定位到问题,要如何解决呢?这里咱们先理解两个名词:
乐观锁(Pessimistic Lock):简略解释就是很乐观,每次去拿数据的时候都认为他人会批改,所以每次在批改数据的时候都会上锁,这样他人想批改这个数据就会期待始终到它能拿到锁。
乐观锁(Optimistic Lock):这个正好相同,就是很乐观,每次去批改数据的时候都认为他人不会批改,所以不会上锁,然而在提交更新的时候会判断一下在此期间他人有没有去更新这个数据。乐观锁实用于读多写少的利用场景,这样能够进步吞吐量。
通过这两种形式就能解决问题,不过选哪种比拟好,咱们来简略剖析下:
乐观锁 通过“select …… for update”实现,就是在更新表前先对这条记录进行上锁,而后上面再执行更新语句。不过这种形式有些太重,毕竟加锁还是须要很大工夫老本的,不合乎业务的须要,间接 pass 掉。
乐观锁 绝对就要轻量很多,它的次要实现就是通过在表中多减少一个记录版本的字段,比方 version。而后每次查问记录要更新时,where 前面都要加上 version=?,这样当你查问拿到 version 后,如果有其余会话更新了这个字段,那这个 version 就会和你当初拿的不一样,从而会使你这次的更新生效,须要从新获取最新 version 后再次执行 update 语句。
问题解决
好了,通过以上剖析,曾经有了比拟清晰的解决思路,剩下就是码代码了:
/**
* 乐观锁更新
* @param id
* @return
*/
public boolean update(int id){
int cnt = 0;
while (cnt == 0) {USER user = query("SELECT * FROM table_user WHERE id = #{id}", id);
cnt = update("UPDATE table_user SET version=version + 1, status = 2 WHERE id=#{id} AND version=#{version}", id, user.version());
if(cnt > 0){
// 返回更新胜利
return true;
}
}
return false;
}
总结
这里只是基于 Mysql 本身个性解决这个问题,当然还有很多其余的形式能够解决
以上就是本次分享的所有内容,想要理解更多 python 常识欢送返回公众号:Python 编程学习圈,每日干货分享