分布式锁-数据库实现

 

1:for update 的原理

select 检索出的数据, for update 加上了一把锁,其他的人是不能修改这个数据的,也不能在给这个数据加锁。其他线程可以检索出来,但是我在用 for update 再给这些数据加锁是加不上的,因为这个锁呢,已经被前一个线程给锁住了。其他人是不能给它加锁的,在加锁的期间,其他人也不能修改这些数据。因为update 更新数据呢,是要获取这些数据的锁的

2:代码实现

    @Transactional(rollbackFor = Exception.class)
    @RequestMapping("/database")
    public String databaseLock () throws InterruptedException {
        log.info("进入方法");
        BusinessLock businessLock = businessLockMapper.getLock("demo");
        if (ObjectUtils.isEmpty(businessLock)) {
            log.info("分布式锁找不到");
        }
        log.info("进入锁");
        Thread.sleep(6000);
        log.info("方法执行完成");
        return "方法执行完成";
    }

 mapper 里面的sql

        SELECT * FROM business_lock WHERE  business_code = #{businessCode}  FOR UPDATE
  •  开启两个实例,端口分别是  8080  8088
  • 下图 8080  应用   
  1. 58:16秒      进入方法
  2. 58:16秒      进入锁
  3. 58:22秒      方法执行完成

 

  • 下图 8088  应用   
  1. 58:17秒      进入方法
  2. 58:22秒      进入锁
  3. 58:28秒      方法执行完成

在代码中我们让获取到锁的应用休眠6秒 ,8080 和 8088 差不多同一时间进入方法,

但是8080更早一些所有获得到了锁,而8088就在数据库中阻塞,等待获取锁。

在16秒 8080获得锁等待6秒 22秒释放锁,这时  8088才拿到了锁。说明在多个应用中锁是有生效的。

教程源码+sql下载

3:用native 测for update

  • 先将当前页面的数据库自动提交先关掉

为什么要先关掉呢?你现在检索出来以后或者for update 加了锁,加了锁以后它马上事务呢就会自动的去提交,事务提交了。锁就会自动释放了。其他的会话,还会检索出这条数据来

  • 下图:默认是自动提交事务的 

  • 下图:这时候都是没有关闭自动提交事务的。两者都可以执行加锁页面。说明没有起到我们想要的作用
  • 下图:关闭两个窗口的自动提交事务
  •  再次检索带有  for update 关键字的sql 。这时候锁被左窗口锁住了,导致右窗口无法加锁。这时候在  左窗口执行commit 提交事务操作,右窗口立马就查询出数据了 。说明锁是生效的

  • 左窗口执行 for update ,右窗口不使用  for update 而是直接执行查询 是可以查询出数据的 

4:总结

 

  

posted @ 2020-10-01 17:10  邱健  阅读(182)  评论(0编辑  收藏  举报