分布式锁实现一. 利用Mysql数据库update锁


分布式锁

1、什么是分布式锁:

分布式锁,即分布式系统中的锁。在单体应用中我们通过锁解决的是控制共享资源访问的问题,而分布式锁,就是解决了分布式系统中控制共享资源访问的问题。与单体应用不同的是,分布式系统中竞争共享资源的最小粒度从线程升级成了进程。

2、分布式锁应该具备哪些条件:

在分布式系统环境下,一个方法在同一时间只能被一个机器的一个线程执行
高可用的获取锁与释放锁
高性能的获取锁与释放锁
具备可重入特性(可理解为重新进入,由多于一个任务并发使用,而不必担心数据错误)
具备锁失效机制,即自动解锁,防止死锁
具备非阻塞锁特性,即没有获取到锁将直接返回获取锁失败

基于数据库的分布式锁

核心代码

@Slf4j
@Component
public class ScheduleJob
{
    private String key = "job001";
    
    @Autowired
    JdbcTemplate jdbcTemplate;
    
    String ip;
    
    /**
     * 初始化
     */
    @PostConstruct
    public void init()
    {
        long count = jdbcTemplate.queryForObject("SELECT count(*) FROM t_schedule_lock WHERE key_name=?", Long.class, key);
        if (count == 0)
        {
            jdbcTemplate.update("INSERT INTO t_schedule_lock(key_name, time) VALUES(?, now())", key);
        }
        try
        {
            ip = InetAddress.getLocalHost().getHostAddress();
        }
        catch (UnknownHostException e)
        {
        }
    }
    
    @Scheduled(cron = "0/10 * * * * ?")
    public void run()
    {
        try
        {
            if (getLock(9L))
            {
                log.info("[{}] #### hello world ***********", ip);
            }
            else
            {
                log.info("[{}] 没抢到,骂骂咧咧的走了......", ip);
            }
        }
        catch (Exception e)
        {
            log.error(e.getMessage(), e);
        }
    }
    
    /**
     * 获取lock,并更新time为下次执行时间 now()+ seconds<BR>
     * 
     * 注意: 为了保证jdbcTemplate.update执行成功,一般设置seconds稍小于@Scheduled设置的运行间隔秒数
     * 
     * @return
     */
    private boolean getLock(long seconds)
    {
        return jdbcTemplate.update("UPDATE t_schedule_lock SET time = adddate(now(), INTERVAL ? SECOND) WHERE key_name = ? AND now() > time", seconds, key) > 0;
    }
}

代码传送

https://gitee.com/00fly/effict-side/tree/master/springboot-locks

项目已经实现了maven插件打包镜像,上传阿里云镜像仓库。

代码运行

下载docker文件下的这2个文件,上传至带有docker-compose以及docker环境的服务器
在这里插入图片描述
运行命令

sh scale.sh

docker ps

docker logs -f <containerId>

运行效果图:
在这里插入图片描述
有任何问题和建议,都可以向我提问讨论,大家一起进步,谢谢!

-over-

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Java,可以利用MySQL的行和事务特性来实现分布式锁。以下是一种基于MySQL实现分布式锁的方案: 1. 创建一个名为`distributed_locks`的表,包含两个字段:`key`和`value`。其`key`表示的名称,`value`表示的状态(0表示未定,1表示已定)。 2. 在Java,创建一个`DistributedLock`类,该类包含以下方法: ``` public class DistributedLock { private static final String LOCK_KEY = "lock_name"; private static final String LOCK_VALUE = "1"; private Connection connection; public DistributedLock(Connection connection) { this.connection = connection; } public boolean lock() throws SQLException { boolean locked = false; connection.setAutoCommit(false); PreparedStatement stmt = connection.prepareStatement("SELECT * FROM distributed_locks WHERE `key` = ? FOR UPDATE"); stmt.setString(1, LOCK_KEY); ResultSet rs = stmt.executeQuery(); if (rs.next()) { int value = rs.getInt("value"); if (value == 0) { PreparedStatement updateStmt = connection.prepareStatement("UPDATE distributed_locks SET `value` = ? WHERE `key` = ?"); updateStmt.setString(1, LOCK_VALUE); updateStmt.setString(2, LOCK_KEY); int updated = updateStmt.executeUpdate(); if (updated == 1) { locked = true; } } } else { PreparedStatement insertStmt = connection.prepareStatement("INSERT INTO distributed_locks (`key`, `value`) VALUES (?, ?)"); insertStmt.setString(1, LOCK_KEY); insertStmt.setString(2, LOCK_VALUE); int inserted = insertStmt.executeUpdate(); if (inserted == 1) { locked = true; } } connection.commit(); connection.setAutoCommit(true); return locked; } public void unlock() throws SQLException { connection.setAutoCommit(false); PreparedStatement stmt = connection.prepareStatement("UPDATE distributed_locks SET `value` = ? WHERE `key` = ?"); stmt.setString(1, "0"); stmt.setString(2, LOCK_KEY); stmt.executeUpdate(); connection.commit(); connection.setAutoCommit(true); } } ``` 3. 以上代码的`lock()`方法实现了获取分布式锁的逻辑。该方法会在`distributed_locks`表查询指定的状态,如果该未被占用,则将其状态更新为已占用,并返回`true`表示获取成功。否则,返回`false`表示获取失败。 4. 上述代码的`unlock()`方法实现了释放分布式锁的逻辑。该方法会将指定的状态更新为未占用。 5. 在业务代码,可以使用以下方式来获取和释放分布式锁: ``` Connection conn = ...; // 获取数据库连接 DistributedLock lock = new DistributedLock(conn); try { if (lock.lock()) { // 获取成功,执行业务逻辑 } else { // 获取失败,执行其他逻辑 } } finally { lock.unlock(); conn.close(); } ``` 需要注意的是,以上代码仅提供了一种基于MySQL实现分布式锁的思路,并不是最佳实践。在实际应用,需要考虑更多的因素,例如超时、死等问题。因此,建议在使用分布式锁时,结合具体场景和实际需求,选择适合自己的方案。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值