java mysql 分布式锁_mysql实现分布式锁

1、最近再学分布式锁,把自己所学的一点心得分享给大家

2、首先介绍我的spring boot项目结构

939a9736-7e38-3a3f-af87-dedb96d58e69.png

数据库表的结构很简单,t_lock表就一个主键字段id

0d2e0d2b-49c0-3366-81c0-af8d2ec230f6.png

3、实现锁的代码

这里运用了模板设计模式

锁接口:

public interface TestLock {

/**

* 加锁

*/

public void getLock();

/**

* 解锁

*/

public void unLock();

}

锁的抽象实现类:

public abstract class AbstractTestLock implements TestLock{

@Override

public void getLock() {

/**

* 1、竞争锁

* 2、占有锁

* 3、任务阻塞

* 4、释放锁

*/

if(tryLock()) {

System.out.println("========获取锁的资源===========");

}else {

//等待

waitLock();

//重新获取资源

getLock();

}

}

public abstract void waitLock();

public abstract boolean tryLock();

}

锁的实现:

@Service

public class MySqlLock extends AbstractTestLock{

@Resource

private LockMapper lockMapper;

private static final Integer ID = 1;

@Override

public boolean tryLock() {

try {

Lock lock = new Lock();

lock.setId(ID);

lockMapper.save(lock);

}catch (Exception e) {

return false;

}

return true;

}

@Override

public void unLock() {

lockMapper.delete(ID);

}

@Override

public void waitLock() {

try {

Thread.currentThread().sleep(10);

}catch (Exception e) {

e.printStackTrace();

}

}

}

仿照订单生成:

public class OrderGenerator {

// 全局订单号

public static int num = 0;

public String getNumber() {

SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");

return sdf.format(new Date())+"-"+ ++num;

}

}

4、测试

public class MysqlLockTest extends LockApplicationTests{

public OrderGenerator generator = new OrderGenerator();

@Resource

private TestLock lock;

@Test

public void testGetOrderNum() throws InterruptedException {

System.out.println("=======生成唯一订单号==========");

for(int i=0; i< 50 ; i++) {

new Thread(

(Runnable) () -> { getNumber(); }

).start();

}

Thread.currentThread().join();

}

private void getNumber() {

try {

lock.getLock();

String number = generator.getNumber();

System.out.println(Thread.currentThread().getName() + ",生成订单ID:"+ number);

}catch (Exception e) {

e.printStackTrace();

}finally {

lock.unLock();

}

}

}

测试结果:

64a812f2-f243-3809-a16a-4de0f68efa55.png

可以看见总共生成了50个订单号,没有重复出现同样的订单号,这样子就实现了用mysql实现分布式锁。

5、使用mysql实现分布式锁的弊端:

a、性能差,无法适应高并发场景,众所周知,mysql的并发瓶颈在300-700之间,当然也有可能达不到,所以一旦并发超过700的话,那么mysql就没法应用于此场景;

b、容易死锁,一旦数据库中数据一开始有数据,那么就会一直处于死锁状态,或者删除数据失败,那么也会一直处于死锁;

c、无法优雅的实现阻塞式锁。

  • 0
    点赞
  • 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、付费专栏及课程。

余额充值