事务并发-幻读实验

156 阅读1分钟

表结构

CREATE TABLE `payment` (
  `id` bigint NOT NULL AUTO_INCREMENT,
  `money` int DEFAULT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci;
INSERT INTO `payment`(`id`, `money`) VALUES (1, 5);

初始数据为id=1,money=5,实验开始,session1与session2执行相同的语句,但执行先后不同

show VARIABLES like 'autocommit';
show variables like '%transaction_isolation%';
set session transaction isolation level repeatable read;
set autocommit = 0;
start TRANSACTION;
SELECT money from payment where id = 1;
update payment set money = money+1 where id = 1;
SELECT money from payment where id = 1;
COMMIT;

image.png 执行如下操作:

  1. session1执行到l1,查看两次select结果,第一次是5,第二次是6,正常逻辑
  2. session2到l2处,会看到查询到了第一次执行结果5,语句阻塞在update(不要卡太久,执行第三步)
  3. session1执行l3,会看到session2的阻塞释放并返回第二次查询结果7
  4. session2执行l4
  5. session1,session2执行l5再次查看结果

结论:

  1. 在repeatable read级别事务并发时,对操作相同的记录会加锁
  2. 在repeatable read级别事务并发时,出现幻读

问题:

  1. 对操作相同的记录,相同如何定义:是主键索引、普通索引、普通字段?
  2. 加的什么锁
  3. 如何解决幻读
  4. 编程时容易出现的bug:将数据取出后在程序中运算再更新
  5. 若问题4中取出数据后要进行复杂的计算,或者需要联表呢,只能使用单纯的update更新,如何防止数据bug