update语句关联的锁机制与利用数据库构造分布式锁

一、update会锁表吗?

1.oracle中,update会形成行锁

update tb_user set phone=11 where name=”c1”;修改,先别commit事务。
重新开另一个窗口,执行select * from tb_user where name = “c1”,可以进行查询。但执行update tb_user set phone=11 where name=”c1”;命令会显示一直在执行中。当第一个update tb_user set phone=11 where name=”c1”;更新语句提交commit后,第二条语句才会执行。

2.oracle利用该机制实现分布式锁

select * from tb_user where name = “C1” for update;
使用在储存过程中。后续再进行提交commit指令。多个实例需要等待第一个实例完成命令后才能进行操作。

3.java利用该机制实现分布式锁

package work;

import com.alibaba.fastjson.JSON;

import java.util.*;

public class OracleSuoStudy {

    // dao层
    private OracleStudy oracleStudy;



    public void beginSuo(){
        try {
            // 当前线程名字
            String lockValue = Thread.currentThread().getName();
            while (! this.lock("studySuo",new Date(System.currentTimeMillis() + 1000*60*10),lockValue)){
                int seconds = 500 + Integer.decode(UUID.randomUUID().toString());
                System.out.println("获取锁失败");
                Thread.sleep(seconds);
            }
            //执行业务代码

        } catch (InterruptedException e) {
            e.printStackTrace();
        } finally {
            // 解锁

        }


    }


    private synchronized boolean lock (String configID, Date aviableTime,String lockValue){
        Map map = new HashMap();
        map.put("configID",configID);
        map.put("aviableTime",aviableTime);
        map.put("lockValue",lockValue);
        // 第一条SQL 查询锁
        Long c = oracleStudy.querySuo(map);
        //第二条SQL  解超时锁
        System.out.println("先尝试解超时锁" + oracleStudy.updateSwitch(map) + ","+ JSON.toJSONString(map));
        boolean flag = false ;

        if (c.intValue() == 0){
            // 第三条SQL创建一个新锁
            oracleStudy.createSuo(map);
            flag = true;
        } else {
            // 第四条SQL,查询锁的状态
            String value = oracleStudy.querySuoStatus(map);
            if (value.equals("1")){
                // 已经加锁
                flag = false;
            } else {
                // 第五条SQL 尝试加锁
                flag = oracleStudy.updateSuostatus(map);
            }

        }
        return flag;

    }
}

Dao层SQL代码

---查看是否存在锁
@Select("select count(1) from config_info  where config_type  = 'djssJobType' and config_id = 'smsSendLock'")
一、querySuo

---尝试解开超时锁
@update("update config_info set config_value = '0' ,updated_date = sysdate where config_type = 'dissJobType' and config_id = 'smsSendLock' and (updated_date < sysdate -1 or Avilable_date < sysdate)")
二、updateSwitch

---第一次执行的时候需要创建锁
@insert("insert into config_info (config_type,config_id,config_value,available_date) values ('djssJobType','smsSendInitLock','1','6000000' || sysdate)")
三、createSuo


----查看锁的状态
@select("select config_value from config_info where config_type = 'djssJobType' and config_id = 'smsSendInitLock'")
四、querySuoStatus


---若锁的状态没有加锁,则对其进行加锁操作
@update("update config_info set config_value = '1',updated_date = sysdate,available = '时间' where config_type = 'djssJobType' and config_value = '0' and config_id = 'smsSendInitLock'")
五、updateSuostatus

2.不带索引

运行命令:begin;开启事务,然后运行命令:update tb_user set phone=11 where name=”c1”;修改,先别commit事务。

再开一个窗口,直接运行命令:update tb_user set phone=22 where name=”c2”;会发现命令卡住了,但是当前面一个事务通过commit提交了,命令就会正常运行结束,说明是被锁表了。

2.带索引

create index index_name on tb_user(name);

然后继续如1里面的操作,也就是一个开启事务,运行update tb_user set phone=11 where name=”c1”;先不提交

然后另一个运行update tb_user set phone=22 where name=”c2”;发现命令不会卡住,说明没有锁表

但是如果另一个也是update tb_user set phone=22 where name=”c1”;更新同一行,说明是锁行了

3.总结

当更新条件有索引时,update会锁行。当更新条件无索引时,update会锁表。

4.扩展查看数据的事务设置

mysq由于默认是开启自动提交事务,所以首先得查看自己当前的数据库是否开启了自动提交事务。

命令:select @@autocommit;

如果结果是1,则说明数据库是自动提交,如果是0则说明数据库没有开启自动提交。

©️2020 CSDN 皮肤主题: 大白 设计师:CSDN官方博客 返回首页