什么是分布式锁?
在弄懂分布式锁之前,我们先搞懂分布式锁最终期望是什么?
在我所了解的是:与多线程一样,保证数据的一致性。
那么来了,分布式锁和多线程什么关系?
若在同一个JVM的前提下,就没必要知道分布式锁是个什么东西,因为在一个JVM下变量是共享的,锁的也是同一个东西,所以加锁或者关键词等等方法可以保证线程的安全。那么不在同一个JVM的前提下,变量也不共享,不能保证我们操作的是一个东西,这就需要借助外界资源,比如关系型数据库:MySql、Oracle,非关系型数据库:Redis,以及Zookeeper等等。我个人认为是这样:只要我能保证这个方法不管在哪个系统中,大环境下是串行的,一个完了再一个即可!
分布式锁-基于数据库方面实现
网上的资源很多,这篇文章我们先从数据库层面进行实现我们分布式锁。
从上面我们了解到,不管在哪个系统上,我们给对象、变量加的都是同一个,此时这个同一个在数据库里应该是唯一约束,只允许出现一次,那么就保证了不管哪个系统操作的都是同一个,剩下的操作需要在我们业务层进行实现。
此时的需求就是:需要一张表用来存我们的信息,以及对应的业务是唯一约束。我们给方法加锁就行。
CREATE TABLE `method_locks` (
`id` int NOT NULL AUTO_INCREMENT COMMENT '主键',
`method_name` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL COMMENT '方法名',
`messages` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL COMMENT '项目以及线程名等等信息',
`create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
PRIMARY KEY (`id`),
UNIQUE KEY `method_names` (`method_name`) USING BTREE COMMENT '唯一约束'
) ENGINE=InnoDB AUTO_INCREMENT=27 DEFAULT CHARSET=utf8;
接下来就需要我们在页面方面处理,具体如下:
利用以前学习Spring Cloud中的资源进行演示:
将服务注册在Eureka集群中:
目前Eureka出过文章,若不了解的话,请参考文章。
通过OpenFeign+Ribbon将请求分发在我们所需要的系统上:
目前Ribbon出过文章,若不了解的话,请参考文章。OpenFeign不了解的话,后续出文章进行简单介绍一下。
具体将要执行的业务程序order8002、order8003
具体看看此时业务是怎么写的,此处是重点,以8002项目为例:
@RequestMapping("/getMyStaff")
public Staff getMyStaff(@RequestParam("staffIdNo") String staffIdNo){
System.out.println("getMyStaff()方法进入:8002........");
// 数据库入参
MethodLocks methodLocks = new MethodLocks();
methodLocks.setMethodName(Thread.currentThread().getStackTrace()[1].getMethodName());
methodLocks.setMessages("8002服务器上的方法被锁定,正在执行....");
Staff staff = null;
try {
methodLocksService.inMethodLocks(methodLocks);
// 具体执行的业务
Thread.sleep(10000);
methodLocksService.deMethodLocks(methodLocks.getMethodName());
} catch (Exception e) {
e.printStackTrace();
//当前方法已经被锁定,无法访问
while (true){
MethodLocks methodLocks1 = methodLocksService.getMethodLocks(Thread.currentThread()
.getStackTrace()[1].getMethodName());
System.out.println("此时的数据为MethodLocks:" + methodLocks1);
System.out.println("等待执行以下方法:"+System.currentTimeMillis());
if (methodLocks1 == null){
methodLocksService.inMethodLocks(methodLocks);
break;
}
}
// 具体执行的业务
Thread.sleep(10000);
methodLocksService.deMethodLocks(methodLocks.getMethodName());
}
return staff;
}
此时访问8002正在进行业务处理:
那么此时的8003肯定在等待状态:
符合我们预期的期望结果顺序,这个就是模拟的基于数据库方面的分布式锁。
不过最好不要采用此种方案进行分布式锁的处理,消耗大量的资源,影响项目效率!
分布式锁-基于Redis方面实现
请参考下一篇文章!
分布式锁-基于Redisson方面实现
请参考下一篇文章!