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();
            // 得到一个批次号
            String batchNo = UUID;
            if(this.lock("studySuo",new Date(System.currentTimeMillis() + 1000*60*10),lockValue,'machine1')){
            // 将批次号为空的批次更新为UUID,更新的时候保证只有一台实例在运行更新
            	oracleStudy.updateBatch(UUID);
                int seconds = 500 + Integer.decode(UUID.randomUUID().toString());
            //执行业务代码
			// 根据批次号,将这批数据查出来
			List<T> list = oracleStudy.queryDataByBatchNo(UUID);
               
            } esle {
		 	log.info("获取锁失败");
            Thread.sleep(seconds);
			}
        } catch (InterruptedException e) {
            e.printStackTrace();
        } finally {
            // 解锁,只能自己解开自己的锁
            oracleStudy.unlock("studySuo","machine1");

        }


    }


    private synchronized boolean lock (String configID, Date aviableTime,String lockValue,String owner){
        Map map = new HashMap();
        map.put("configID",configID);
        map.put("aviableTime",aviableTime);
        map.put("lockValue",lockValue);
        map.put("owner",owner);
        // 第一条SQL 查询锁
        Long c = oracleStudy.querySuo(map);
        //第二条SQL  解超时锁
        log.info("先尝试解超时锁" + 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 = '时间',owner = 'machine1' where config_type = 'djssJobType' and config_value = '0' and config_id = 'smsSendInitLock'")
五、updateSuostatus

@update("update config_info set config_value = '0',updated_date = sysdate where config_type = 'djssJobType' and onwer = 'machine1' and config_id = 'smsSendInitLock'"
)
六、unlock解锁操作
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则说明数据库没有开启自动提交。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
以下是基于数据库分布式锁的Java代码示例: ```java public class DistributedLock { private static final String LOCK_NAME_PREFIX = "distributed_lock_"; private final DataSource dataSource; private final String lockName; public DistributedLock(DataSource dataSource, String lockName) { this.dataSource = dataSource; this.lockName = LOCK_NAME_PREFIX + lockName; } public boolean acquire() { try (Connection connection = dataSource.getConnection()) { connection.setAutoCommit(false); // Insert a new row with the lock name try (PreparedStatement statement = connection.prepareStatement( "INSERT INTO locks (name) VALUES (?) ON CONFLICT DO NOTHING")) { statement.setString(1, lockName); statement.executeUpdate(); } // Try to acquire the lock by updating the row with a unique value try (PreparedStatement statement = connection.prepareStatement( "UPDATE locks SET acquired_by = ? WHERE name = ? AND acquired_by IS NULL")) { statement.setString(1, UUID.randomUUID().toString()); statement.setString(2, lockName); int rowsUpdated = statement.executeUpdate(); if (rowsUpdated == 1) { connection.commit(); return true; } } connection.rollback(); return false; } catch (SQLException e) { throw new RuntimeException("Unable to acquire lock", e); } } public void release() { try (Connection connection = dataSource.getConnection(); PreparedStatement statement = connection.prepareStatement( "UPDATE locks SET acquired_by = NULL WHERE name = ?")) { statement.setString(1, lockName); statement.executeUpdate(); } catch (SQLException e) { throw new RuntimeException("Unable to release lock", e); } } } ``` 在此示例中,我们使用了一个名为“locks”的数据库表来存储锁的信息。该表包含一个“name”列和一个“acquired_by”列。当我们尝试获取锁时,我们首先插入一个新行,然后尝试通过更新该行来获取锁。如果更新成功,则表示我们已经获得了锁,并且可以提交事务。如果更新失败,则表示其他进程已经获得了锁,并且必须回滚事务。释放锁时,我们只需要更新“acquired_by”列为NULL即可。 请注意,此代码示例仅用于演示目的。在实际生产环境中,您需要考虑更多方面,例如锁超时、死锁检测等。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值