文 | 極光

来源:Python 技术「ID: pythonall」


最近开发中遇到个小问题,因为业务上的设计存在问题,导致数据库表总是被锁,而且是不定期的锁定,导致服务器运行异常,最后经过排查原因是多线程同时更新同一表中同一条记录导致问题。今天就来跟大家说说该如何避免这种问题。

问题描述

最近因为公司业务需要,产品设计了一套业务系统,据说会有很多内部和外部人员使用,拿到系统说明我们研发部门拼命加班赶时间,经历了两个月的后终于把系统上线运行。

刚开始用的人少,并没有出现什么问题,感觉系统还是很稳定,随着后来用的人越来越多,系统就开始出现一些莫名其妙的问题,其中就有某些业务信息在更新的时候总是报错,查日志就发现是表记录被锁定导致更新失败。

找到错误问题后我们就开始一遍遍的翻日志,各种分析查找到底是什么原因导致了表记录被锁。最后发现这个表的状态字段,存在多个接口方法同时更新的情况,而且经常是同时操作的。也就是数据库中存在多个会话同时操作同一表中同一行记录,从而导致表记录被锁。

问题分析

那定位到问题,要如何解决呢?这里我们先了解两个名词:

悲观锁(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 自身特性解决这个问题,当然还有很多其他的方式可以解决,例如通过 Redis 或者 MQ 消息队列等,如果大家感兴趣我们可以以后再介绍。OK,这次就聊这些,如果你喜欢记得点 在看。

©著作权归作者所有:来自51CTO博客作者mob604756e8ada8的原创作品,如需转载,请注明出处,否则将追究法律责任

更多相关文章

  1. 【大数据成神之路】第一版更新完毕
  2. ensp起不来的原因汇总(长期更新)
  3. 【鸿蒙学院】鸿蒙IDE迎来重大更新,新特性足以让你尖叫
  4. Apache Kafka 2.0.0 正式发布,多项重要功能更新
  5. 电脑用户需要了解的Win7与Win10系统知识
  6. 深夜更新 - 一文读懂MQ消息队列
  7. 深度系统更新(2020.11.11)
  8. 深度系统更新(deepin 20 1003)
  9. 深度系统更新(2020.11.13)

随机推荐

  1. Android EditText 的 android:imeOptions
  2. ProgressBar用法
  3. Android布局属性大全
  4. Android Bluetooth初始化流程
  5. android selector 中的几个关键状态
  6. android 权限示例
  7. Android ZoomControls的使用
  8. ADT下载地址(含各版本)(转)
  9. 安装Android SDK时遇到Failed to rename
  10. Android与JS互调