事务遇上分布式锁
1.分布式锁的几种实现方式
- 直接使用MySQL进行同步异常处理
- redis Lua脚本或者redison
- zookeeper原子树结构
2. MySQL使用自带锁进行分布式同步控制
mysql加锁方式,todo。
2.1 环境准备
DROP TABLE IF EXISTS `metering`;
CREATE TABLE `metering` (
`id` bigint(20) UNSIGNED NOT NULL AUTO_INCREMENT,
`name` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL DEFAULT '',
`rest` double(20, 2) NOT NULL DEFAULT 0.00,
`version` bigint(20) UNSIGNED NOT NULL DEFAULT 0,
`remark` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL DEFAULT '',
PRIMARY KEY (`id`) USING BTREE
) ENGINE = InnoDB AUTO_INCREMENT = 5 CHARACTER SET = utf8 COLLATE = utf8_general_ci ROW_FORMAT = Compact;
-- ----------------------------
-- Records of metering
-- ----------------------------
INSERT INTO `metering` VALUES (1, '小碗熊干脆面', 100.00, 0, '');
INSERT INTO `metering` VALUES (2, '魔法师干脆面', 100.00, 0, '');
INSERT INTO `metering` VALUES (3, '飞旺辣条', 100.00, 0, '');
INSERT INTO `metering` VALUES (4, '绿箭辣条', 100.00, 0, '');
输入以下命令查看隔离级别
show variables like 'tx_isolation';
输入以下命令查看是否自动提交事务
show variables like 'autocommit';
ON 自动提交 OFF不是自动提交
修改自动提交状态:
set autocommit=on;
手动提交命令
start transaction;
SQL;
commit;
2.2 可重复读下的for update的验证
在可重复读隔离级别下读不到别的事务还未提交的内容,并且在事务未提交之前都是对事务开启时刻的数据的快照读,即读不到别的事务已经修改的内容,这样就导致了使用version 字段的时候普通select 无法读最新数据。
事务1 | 事务2 |
---|---|
start transaction; | |
start transaction; | |
![]() |
|
![]() |
|
![]() |
|
![]() |
|
![]() |
|
![]() |
有一种强制读的办法就是加for update,但如果别的事务没有提交修改内容就会处于等待锁的过程中。
同时需注意的是,如果没有开启事务,如果事务1获取到X锁,在未开启事务场景下的事务2使用for update 会阻塞,而且也是属于快照读。读不到事务1未提交的内容,但是不加for update时可以读到已经提交的内容,验证结果如下:
事务1 | 未开事务 |
---|---|
![]() |
|
![]() |
|
![]() |
|
![]() |
|
![]() |
验证2,事务外可读事务已提交内容:
事务1 | 未开事务 |
---|---|
![]() |
|
![]() |
|
![]() |
|
![]() |
如果在for update 加X锁读的时候不是按照索引来读的,则会锁表。
事务1 | 未开事务 |
---|---|
![]() |
|
![]() |
|
![]() |
所以使用X锁在innodb引擎下注意要和索引进行使用。
3.Redis使用分布式锁
todo
本图文内容来源于网友网络收集整理提供,作为学习参考使用,版权属于原作者。
THE END
二维码