注意:

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 ASession 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,只查询出来一条,这时事务Bid<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高级课程,在此表示感谢,如有侵权,请联系站长进行删除
<声明>:

谁都不是生下来就会的,都不是三体人,知识也可以遗传,我们的东西都是学习到的,所以每个人的知识体系难免有老师的身影,先学习后模仿,才能学会,至于笔记,摘抄部分我感觉难免,学会了就是自己的!

分类: javamysql

2 条评论

xiaosheng · 2023-07-19 16:08

给自己点个赞吧

    xiaosheng · 2023-07-19 21:12

    我太棒了,加油!

评论已关闭。

浙公网安备33011302000604

辽ICP备20003309号