mysql实现分布式锁
1、最近再学分布式锁,把自己所学的一点心得分享给大家
2、首先介绍我的spring boot项目结构
数据库表的结构很简单,t_lock表就一个主键字段id
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();
}
}
}
测试结果:
可以看见总共生成了50个订单号,没有重复出现同样的订单号,这样子就实现了用mysql实现分布式锁。
5、使用mysql实现分布式锁的弊端:
a、性能差,无法适应高并发场景,众所周知,mysql的并发瓶颈在300-700之间,当然也有可能达不到,所以一旦并发超过700的话,那么mysql就没法应用于此场景;
b、容易死锁,一旦数据库中数据一开始有数据,那么就会一直处于死锁状态,或者删除数据失败,那么也会一直处于死锁;
c、无法优雅的实现阻塞式锁。