分布式锁的几种常见实现方式
数据库乐观锁 实现方式 用表中一行记录来表示锁,其中表示锁的字段采用唯一约束 当多个线程同时执行插入语句时,只有一个能插入成功,可以认为获得到了锁,其他则会报错:ERROR 1062 (23000): Duplicate entry ‘1’ for key ‘uiq_idx_resource’),这种情况可以认为没有获得到锁 当需要释放锁时,可以删除这一条记录就可以了 这种锁的特点: 锁没有失效时间,一旦锁释放失败,便会一直留在数据库中,影响其他线程获取锁。可以采用定时任务对其进行清理 锁依赖数据库,需要考虑单点故障问题。同时也要考虑给数据库性能带来的影响 锁是非阻塞的,一旦插入失败,直接便会报错,需要采用轮询的方式来实现 锁也是非可重入的,一旦一个线程获取到了锁,由于数据库中已经存在了这一条记录,其本身也不能再次获取到这个锁。这一点可以将主机和线程信息存入数据库,如果存在锁,并且锁也归属于当前线程,则可以将此锁再次分配给它 Redis实现 基本上基于setnx命令实现 SETNX 是SET if Not eXists的简写 解释: 当且仅当 key 不存在,将 key 的值设为 value,返回1; 若给定的 key 已经存在,则 SETNX 不做任何动作,返回0。 @Component public class RedisService { @Autowired private RedisTemplate<String,String> redisTemplate; private static final String COMPARE_AND_DELETE = "if redis.call('get', KEYS[1]) == ARGV[1] then return redis.call('del', KEYS[1]) else return 0 end"; public Boolean getLock(String key,String value){ return redisTemplate.opsForValue().setIfAbsent(key, value, 2, TimeUnit.MINUTES); } public void releaseLock(String key,String value){ List<String> keys = Collections.singletonList(key); redisTemplate.execute(new DefaultRedisScript<>(COMPARE_AND_DELETE,Long.class), keys, value); } } 这里并没有直接使用delete命令,是为了防止删除其他线程的key。、 ...