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();
}
?锁的实现:
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、无法优雅的实现阻塞式锁。
?