Mysql
1.单机环境下
1.悲观锁
select * from table where id = * for update
查询语句末尾添加for update 会对数据添加行锁(数据量小的时候容易出现表锁的情况,所以最好是有 where id = * 条件)然后搭配事务注解 实现单库单表情况下的锁
2.乐观锁
添加version字段,每次更新成功后version+1
在更新数据前,判断当前数据库数据的version跟方法中的version值是否一致,一致则更新,不一致则失败 非读写分离下可用
2.分布式环境下
增加lock表,并将锁名作为唯一索引,当进程开始时,向lock表中插入数据,成功则代表获得锁,执行方法,执行完毕后释放锁(删除数据),失败则代表无法获得锁,只能进行重试
缺陷:容易产生死锁,无法可重复入锁,且依赖数据库性能,并发问题严重无法解决
Redis(内存处理相较于MySQL磁盘处理速度更快)
1.单机环境
setnx命令(不存在则插入,存在则返回false)
当进程开始时,向Redis中插入数据(需要设置时间,防止出现死锁现象),成功则获得锁,执行方法,执行完毕后释放锁(删除数据),失败则代表无法获得锁,只能进行重试
性能提升——分段锁机制
根据id进行分段的一种操作,如数据库种id为1-10的数据,使用Redis中可用为id-1的锁,10-20使用Redis中id-2的锁,进行一种分段操作
缺陷:过期时间会出现2种问题
1.过期任务未执行完,锁已经释放,如何续期
2.过期后任务执行完毕,删除了正在执行的其他请求的锁
2.分布式集群环境
问题:集群条件下,主从Redis无法做到数据实时同步,可能会导致Redis锁出现问题
解决:红锁机制(redisson提供,但是需要5台Redis服务器为保底)
红锁机制讲究提供5台及其以上的奇数Redis服务器,使用redisson的检测机制,超过一般的Redis台数上得到成功结果,则判定为可以获得锁,否则失败
缺陷:
1.Redis宕机一台立刻重启后可能会造成冲突,导致另外一台斧王可以获得锁,所以无法立刻重启
2.Java的STW机制(JVM运行过程中,所有的应用线程都会被暂停,JVM会执行一些特定的任务,如垃圾回收、线程栈的调整等),会另外一台服务可以获得锁
Zookeeper
事件监听:监听zk下所有的节点的变化
机制:顺序节点与临时节点
特性:zk的节点具有互斥性,唯一性,当一个节点被创建,就不能在创建
临时节点:当程序与zk进行连接的时候,所创造的节点,就是临时节点,断开后节点则消失
顺序节点:zk进行连接时,所有的节点都是按照连接先后,进行一个排序,则称为顺序节点