一、版本号解决冲突
对表增加版本号,每次更新,进行版本号比较,相同则更新,并且版本号+1,否则更新失败。避免多线程查出这条数据后,同时间对这一条数据进行操作,造成数据覆盖(即ABA覆盖的问题)
更新失败,让发起方重新发起
二、表中冗余锁字段
在表中增加两个字段,例如锁业务流水号,锁时间【避免表锁,一定要命中索引,转为行锁】
1、当多个发起方调用接口准备更新同一条数据的时候
2、加锁,封装为LockUtil【该逻辑与redis分布式锁逻辑差不多,只是操作对象不一样,一个缓存一个DB】
lock
在一个事务中,通过forupdate查这条数据,判断锁业务流水号,锁时间是否为空
如果为空,则说明这条数据可操作,为锁业务流水号,锁时间赋值,更新记录,并返回true
如果不为空,则说明这条数据已被其他发起方占用了,比较锁业务流水号与发起方的流水号是否一致,一致则为重入,返回true,不一致,则判断锁时间是否过期(限定时间范围),过期则进行抢占,为锁业务流水号,锁时间赋值,更新记录,并返回true,否则返回false
3、根据lock返回,进行相关的业务操作
4、解锁,封装为LockUtil【finally解锁】
在一个事务中,通过forupdate查这条数据,判断锁业务流水号,锁时间是否为空
如果为空,打error日志告警
如果不为空,比较锁业务流水号与发起方的流水号是否一致,一致则将锁业务流水号,锁时间更新为空,否则打error日志告警
三、记录锁
新建一张表,用于存储各种业务锁,操作过程与二差不多。只是落到专属的记录表中(自定义粗细粒度锁,以及各个场景汇总)
如果是先初始化好锁记录,可有专属的配置信息存于表中。例如xxx锁,失效时间,是否可重入等
四、事务控制
直接通过事务控制,将整个操作逻辑都包在事务中,相当于悲观锁了,这样可能会引发长事务,或者死锁
五、redis分布式锁
使用redis做分布式锁,目前市面上提供了redisson,已封装好逻辑,不需要自己实现,具体百度