# 代码篇:学会13 种锁,从此不再为“锁”心烦
作者:Tom哥
公众号:微观技术
博客:https://offercome.cn (opens new window)
人生理念:知道的越多,不知道的越多,努力去学
分布式系统时代,线程并发,资源抢占,"锁" 慢慢变得很重要。
那么常见的锁都有哪些?
今天Tom哥就和大家简单聊聊这个话题
# 1、悲观锁
正如其名,它是指对数据修改时持保守态度,认为其他人也会修改数据。因此在操作数据时,会把数据锁住,直到操作完成。
悲观锁大多数情况下依靠数据库的锁机制实现,以保证操作最大程度的独占性。如果加锁的时间过长,其他用户长时间无法访问,影响程序的并发访问性,同时这样对数据库性能开销影响也很大,特别是长事务而言,这样的开销往往无法承受。
如果是单机系统,我们可以采用 JAVA 自带的 synchronized 关键字,通过添加到方法或同步块上,锁住资源
如果是分布式系统,我们可以借助数据库自身的锁机制来实现
select * from 表名 where id= #{id} for update
使用悲观锁的时候,我们要注意锁的级别,MySQL innodb 在加锁时,只有明确的指定主键或(索引字段)才会使用 行锁 ;否则,会执行 表锁 ,将整个表锁住,此时性能会很差。
在使用悲观锁时,我们必须关闭 MySQL 数据库的自动提交属性,因为mysql默认使用自动提交模式。悲观锁适用于写多的场景,而且并发性能要求不高
# 2、乐观锁
乐观锁,从字面意思也能猜到个大概,在操作数据时非常乐观,认为别人不会同时修改数据,因此乐观锁不会上锁 只是在 提交更新 时,才会正式对数据的冲突与否进行检测。如果发现冲突了,则返回错误信息,让用户决定如何去做,fail-fast 机制 。否则,执行本次操作。
分为三个阶段:数据读取、写入校验、数据写入。
如果是单机系统,我们可以基于JAVA 的 CAS来实现,CAS 是一种原子操作,借助硬件的比较并交换来实现。 如果是分布式系统,我们可以在数据库表中增加一个 版本号 字段,如:version
update 表 set ... , version = version +1 where id= #{id} and version = #{version}