REPEATABLE-READ:可重复读
将隔离级别置为REPEATABLE-READ
# 隔离级别设置,READ-UNCOMMITTED读未提交,READ-COMMITTED读已提交,REPEATABLEREAD可重复读,SERIALIZABLE串⾏
transaction-isolation=REPEATABLE-READ
重启mysql:
C:\Windows\system32>net stop mysql
mysql 服务正在停⽌..
mysql 服务已成功停⽌。
C:\Windows\system32>net start mysql
mysql 服务正在启动 .
mysql 服务已经启动成功。
查看隔离级别:
mysql> show variables like 'transaction_isolation';
+-----------------------+----------------+
| Variable_name | Value |
+-----------------------+----------------+
| transaction_isolation | REPEATABLE-READ |
+-----------------------+----------------+
1 row in set, 1 warning (0.00 sec)
先清空test1表数据:
delete from test1;
select * from test1;
按时间顺序在2个窗⼜中执⾏下⾯操作:| 1 |
+------+
2 rows in set (0.00 sec)
B窗⼜如下:
mysql> start transaction;
Query OK, 0 rows affected (0.00 sec)
mysql> insert into test1 values (1);
Query OK, 1 row affected (0.00 sec)
mysql> select * from test1;
+------+
| a |
+------+
| 1 |
| 1 |
+------+
2 rows in set (0.00 sec)
mysql> commit;
Query OK, 0 rows affected (0.00 sec)
看⼀下:
T2-A、T6-A窗⼜:⽆数据,T5-B:有数据,A看不到B的数据,说明没有脏读。
T8-A:⽆数据,此时B已经提交了,A看不到B已提交的数据,A中3次读的结果⼀样都是
没有数据的,说明可重复读。
结论:可重复读情况下,未出现脏读,未读取到其他事务已提交的数据,多次读取结果⼀
致,即可重复读。
幻读演示
幻读只会在REPEATABLE-READ(可重复读)级别下出现,需要先把隔离级别改为可重复
读。将隔离级别置为REPEATABLE-READ
# 隔离级别设置,READ-UNCOMMITTED读未提交,READ-COMMITTED读已提交,REPEATABLEREAD可重复读,SERIALIZABLE串⾏
transaction-isolation=REPEATABLE-READ
重启mysql:
C:\Windows\system32>net stop mysql
mysql 服务正在停⽌..
mysql 服务已成功停⽌。
C:\Windows\system32>net start mysql
mysql 服务正在启动 .
mysql 服务已经启动成功。
查看隔离级别:
mysql> show variables like 'transaction_isolation';
+-----------------------+----------------+
| Variable_name | Value |
+-----------------------+----------------+
| transaction_isolation | REPEATABLE-READ |
+-----------------------+----------------+
1 row in set, 1 warning (0.00 sec)
准备数据:
mysql> create table t_user(id int primary key,name varchar(16) unique
key);
Query OK, 0 rows affected (0.01 sec)
mysql> insert into t_user values (1,'路⼈甲Java'),(2,'路⼈甲Java');
ERROR 1062 (23000): Duplicate entry '路⼈甲Java' for key 'name'
mysql> select * from t_user;
Empty set (0.00 sec)
上⾯我们创建t_user表,name添加了唯⼀约束,表⽰name不能重复,否则报
错。A窗⼜如下:
mysql> start transaction;
Query OK, 0 rows affected (0.00 sec)
mysql> select * from t_user where name='路⼈甲Java';
Empty set (0.00 sec)
mysql> insert into t_user values (2,'路⼈甲Java');
ERROR 1062 (23000): Duplicate entry '路⼈甲Java' for key 'name'
mysql> select * from t_user where name='路⼈甲Java';
Empty set (0.00 sec)
mysql> commit;
Query OK, 0 rows affected (0.00 sec)
B窗⼜如下:
mysql> start transaction;
Query OK, 0 rows affected (0.00 sec)
mysql> insert into t_user values (1,'路⼈甲Java');
Query OK, 1 row affected (0.00 sec)
mysql> select * from t_user;
+----+---------------+
| id | name |
+----+---------------+
| 1 | 路⼈甲Java |
+----+---------------+
1 row in set (0.00 sec)
T
9
c
o
m
m
it
;mysql> commit;
Query OK, 0 rows affected (0.00 sec)
看⼀下:
A想插⼊数据路⼈甲Java,插⼊之前先查询了⼀下(T5时刻)该⽤户是否存在,发现不存
在,然后在T7时刻执⾏插⼊,报错了,报数据已经存在了,因为T6时刻B已经插⼊了路⼈
甲Java。
然后A有点郁闷,刚才查的时候不存在的,然后A不相信⾃⼰的眼睛,又去查⼀次(T8时
刻),发现路⼈甲Java还是不存在的。
此时A⼼⾥想:数据明明不存在啊,为什么⽆法插⼊呢?这不是懵逼了么,A觉得如同发
⽣了幻觉⼀样。
SERIALIZABLE:串⾏
SERIALIZABLE会让并发的事务串⾏执⾏(多个事务之间读写、写读、写写会产
⽣互斥,效果就是串⾏执⾏,多个事务之间的读读不会产⽣互斥)。
读写互斥:事务A中先读取操作,事务B发起写⼊操作,事务A中的读取会导致事
务B中的写⼊处于等待状态,直到A事务完成为⽌。
表⽰我开启⼀个事务,为了保证事务中不会出现上⾯说的问题(脏读、不可重复
读、读已提交、幻读),那么我读取的时候,其他事务有修改数据的操作需要排
队等待,等待我读取完成之后,他们才可以继续。
写读、写写也是互斥的,读写互斥类似。
这个类似于java中的
java.util.concurrent.lock.ReentrantReadWriteLock类产⽣的效果。
下⾯演⽰读写互斥的效果。
将隔离级别置为SERIALIZABLE
# 隔离级别设置,READ-UNCOMMITTED读未提交,READ-COMMITTED读已提交,REPEATABLEREAD可重复读,SERIALIZABLE串⾏
transaction-isolation=SERIALIZABLE重启mysql:
C:\Windows\system32>net stop mysql
mysql 服务正在停⽌..
mysql 服务已成功停⽌。
C:\Windows\system32>net start mysql
mysql 服务正在启动 .
mysql 服务已经启动成功。
查看隔离级别:
mysql> show variables like 'transaction_isolation';
+-----------------------+--------------+
| Variable_name | Value |
+-----------------------+--------------+
| transaction_isolation | SERIALIZABLE |
+-----------------------+--------------+
1 row in set, 1 warning (0.00 sec)
先清空test1表数据:
delete from test1;
select * from test1;
按时间顺序在2个窗⼜中执⾏下⾯操作:
时
间
窗
⼜
A
窗
⼜
B上⾯这个演⽰的是读写互斥产⽣的效果,⼤家可以⾃⼰去写⼀下写读、写写互斥的效果。
可以看出来,事务只能串⾏执⾏了。串⾏情况下不存在脏读、不可重复读、幻读的问题
了。
关于隔离级别的选择
1. 需要对各种隔离级别产⽣的现象⾮常了解,然后选择的时候才能游刃有余
2. 隔离级别越⾼,并发性也低,⽐如最⾼级别SERIALIZABLE会让事物串⾏执⾏,并发
操作变成串⾏了,会导致系统性能直接降低。
3. 具体选择哪种需要结合具体的业务来选择。
4. 读已提交(READ-COMMITTED)通常⽤的⽐较多。
总结
1. 理解事务的4个特性:原⼦性、⼀致性、隔离性、持久性
2. 掌握事务操作常见命令的介绍
3. set autocommit可以设置是否开启⾃动提交事务
4. start transaction:开启事务
5. start transaction read only:开启只读事物
6. commit:提交事务
7. rollback:回滚事务
8. savepoint:设置保存点
9. rollback to 保存点:可以回滚到某个保存点
10. 掌握4种隔离级别及了解其特点11. 了解脏读、不可重复读、幻读