注意:
mysql
默认使用的是可重复读 REPEATABLE READ
隔离级别,如果从定义的角度来看,可重复读隔离级别解决了脏读, 不可重复读的问题,没有解决幻读的问题
, 但由于 mysql
采用了 MVCC
,读的是一个快照,所以它不光解决了 脏读, 不可重复读的问题,还解决了幻读的问题
,mysql
可重复读隔离级别解决了串行化才解决的问题 ,这不意味着他变成串行化了, 串行化是用锁的方式来实现的,MVCC
可以不采用锁的方式,而是通过乐观锁的方式来解决 不可重复读 和 幻读的问题,他可以在大多数情况下替代行级锁,降低系统开销
数据并发问题
脏写
对于两个事务 Session A、Session B
,如果事务Session A
修改了 另一个 未提交 事务Session B
修改过 的数据,那就意味着发生了 脏写
脏读
对于两个事务 Session A、Session B。 Session A
读取 了已经被Session B
更新 但还 没有被提交 的数据。之后若 Session B
回滚 ,Session A
读取 的内容就是 临时且无效 的。
Session A
和Session B
各开启了一个事务,Session B
中的事务先将studentno
列为1
的记录的name列更新为’张三’,然后Session A
中的事务再去查询这条studentno
为1的记录,如果读到列name的值为’张三’,而Session B
中的事务稍后进行了回滚,那么Session A
中的事务相当于读到了一个不存在的数据,这种现象就称之为 脏读 。
不可重复读
两个事务,A , B
,他们读取了同一字段,但B
事务比较贱,他把这个字段更新了,A
再读取这个字段发现值不同了。
幻读
xx表中只有一条数据,id = 5
。
A
事务执行了一个sql
: select * from xx where id < 12
,只查询出来一条,这时事务B
在id<12
这个范围插入了两条id=7 id=8
的数据,A
再进行读取,发现变多了。
严重性
脏写 > 脏读 > 不可重复读 > 幻读
脏写的问题必须解决!!!
隔离级别
READ UNCOMMITTED
:读未提交,在该隔离级别,所有事务都可以看到其他未提交事务的执行结果。不能避免脏读、不可重复读、幻读。-
READ COMMITTED
:读已提交,它满足了隔离的简单定义:一个事务只能看见已经提交事务所做的改变。这是大多数数据库系统的默认隔离级别(但不是MySQL
默认的)。可以避免脏读,但不可重复读、幻读问题仍然存在。 -
REPEATABLE READ
:可重复读,事务A在读到一条数据之后,此时事务B对该数据进行了修改并提交,那么事务A再读该数据,读到的还是原来的内容。可以避免脏读、不可重复读,但幻读问题仍然存在。这是MySQL
的默认隔离级别。 -
SERIALIZABLE
:可串行化,确保事务可以从一个表中读取相同的行。在这个事务持续期间,禁止其他事务对该表执行插入、更新和删除操作。所有的并发问题都可以避免,但性能十分低下。能避免脏读、不可重复读和幻读。
可以看到脏写没有涉及,因为脏写问题太严重了,不管那种隔离级别都不允许这种事情的发生!
mysql
支持这四种隔离级别!
隔离级别设置 & 查看
查看
# 查看隔离级别,MySQL 5.7.20的版本之前:
mysql> SHOW VARIABLES LIKE 'tx_isolation';
+---------------+-----------------+
| Variable_name | Value |
+---------------+-----------------+
| tx_isolation | REPEATABLE-READ |
+---------------+-----------------+
1 row in set (0.00 sec)
# MySQL 5.7.20版本之后,引入transaction_isolation来替换tx_isolation
# 查看隔离级别,MySQL 5.7.20的版本及之后:
mysql> SHOW VARIABLES LIKE 'transaction_isolation';
+-----------------------+-----------------+
| Variable_name | Value |
+-----------------------+-----------------+
| transaction_isolation | REPEATABLE-READ |
+-----------------------+-----------------+
1 row in set (0.02 sec)
#或者不同MySQL版本中都可以使用的:
SELECT @@transaction_isolation;
设置
SET [GLOBAL|SESSION] TRANSACTION ISOLATION LEVEL 隔离级别;
#其中,隔离级别格式:
> READ UNCOMMITTED
> READ COMMITTED
> REPEATABLE READ
> SERIALIZABLE
或者
SET [GLOBAL|SESSION] TRANSACTION_ISOLATION = '隔离级别'
#其中,隔离级别格式:
> READ-UNCOMMITTED
> READ-COMMITTED
> REPEATABLE-READ
> SERIALIZABLE
关于设置时使用GLOBAL或SESSION的影响
- 使用 GLOBAL 关键字(在全局范围影响):
SET GLOBAL TRANSACTION ISOLATION LEVEL SERIALIZABLE;
#或
SET GLOBAL TRANSACTION_ISOLATION = 'SERIALIZABLE';
使用 GLOBAL 关键字则:
- 当前已经存在的会话无效
- 只对执行完该语句之后产生的会话起作用
- 使用 SESSION 关键字(在会话范围影响):
SET SESSION TRANSACTION ISOLATION LEVEL SERIALIZABLE;
#或
SET SESSION TRANSACTION_ISOLATION = 'SERIALIZABLE';
使用 SESSION 关键字则:
- 对当前会话的所有后续的事务有效
- 如果在事务之间执行,则对后续的事务有效
- 该语句可以在已经开启的事务中间执行,但不会影响当前正在执行的事务
总结
数据库规定了多种事务隔离级别,不同隔离级别对应不同的干扰程度,隔离级别越高,数据一致性
就越好,但并发性越弱。
参考文献
文章部分内容引用自宋红康老师的Mysql高级课程,在此表示感谢,如有侵权,请联系站长进行删除
<声明>:
谁都不是生下来就会的,都不是三体人,知识也可以遗传,我们的东西都是学习到的,所以每个人的知识体系难免有老师的身影,先学习后模仿,才能学会,至于笔记,摘抄部分我感觉难免,学会了就是自己的!
2 条评论
xiaosheng · 2023-07-19 16:08
给自己点个赞吧
xiaosheng · 2023-07-19 21:12
我太棒了,加油!
评论已关闭。