SQL_MVCC事务隔离级别
铺垫:
事务隔离级别:
1、脏读:其实就是不满足数据库事务的隔离性,
A操作还未提交时,B操作就已经读到了A操作后的数据,A而后将操作进行了回滚,那么B操作读到的数据就是错误的,
读已提交的隔离级别就是用来处理脏读的问题
2、不可重复读:
同一个事务中,多次读取相同的数据,但是读取的结果不一致,会在本事务中产生数据不一致的问题,
比如在A事务中,多次读取数据间隔中,B事务对数据进行了修改,那么A事务多次读取相同的数据就会产生数据不一致的问题,这就是不可重复读
可重复读的隔离级别就是用来处理不可重复读的问题:以下是对可重复读的隔离级别的解释
可重复读(Repeatable Read):在同一个事务内,如果你执行了两次相同的SELECT语句,那么即使在这两个SELECT语句之间有其他的事务更新了数据,你也会得到同样的结果。这是因为在这个隔离级别下,数据库系统会记住事务开始时的数据状态,并在事务结束前的所有查询中使用这一快照。
这其实体现的也是数据库事务的隔离性,在两个事务没有结束前(数据库事务的结束以commit提交为标准),两个事物互不干扰
这个级别的一个常见实现方式是在读取数据时锁定数据行,直到事务结束。这种方式可以避免脏读和不可重复读,但可能会导致死锁的情况。
避免的问题:
但是,“可重复读”隔离级别并不能防止另一种现象,即幻读(Phantom Reads),指的是在同一事务内,由于其他事务插入了新的记录,导致查询结果集中的记录数量发生了变化。
脏读(Dirty Reads):一个事务读取了另一个未提交事务的数据。
不可重复读(Non-repeatable Reads):一个事务内多次读取同一行数据,第二次读取时发现该数据已被另一个事务更改。
也就是说可重复读的数据库隔离级别比读已提交的隔离界别高
注意可重复读针对的是行锁,A和B事务都对单行进行操作
3、幻读
A事务比方说对整张表进行查询,在多次查询的事务中,B事务对进行插入,那么A事务多次查询到的数据不一致,这就是幻读
串行化对要操作的表加锁,可以用来解决幻读
锁的粒度太粗,当某张表被串行化,那么其他事务会阻塞等待,会大大影响并发性能
幻读和脏读非常像,区别是可重复读的隔离级别是对针对某一行数据(并不是行级索,而是对),串行化是对整张表上锁
-
定义:
- 在串行化隔离级别下,事务要么按照某个固定的顺序依次执行,要么是通过使用足够多的锁来确保事务之间没有重叠的操作区间,从而达到顺序执行的效果。
- 也就是说,任何时刻只有一个事务可以访问数据,其他事务必须等待当前事务完成并释放锁后才能继续。
串行化的颗粒度更高,串行化我的理解是表级锁,
问题:数据库事务中,如果A和B同时对某个表的同一行进行操作,那么应该使用可重复读锁
操作:
在进行操作前对数据库的隔离级别进行设置
MySQL的默认事务隔离级别是可重复读
Oracle 的默认事务隔离级别是读已提交
MySQL使用的可重复读,并不是使用行级锁来实现,这样会导致事务由并行变为串行,降低数据库的并发性能
而是使用了MVCC的无锁机制,其本质是数据库系统创建一个数据的快照,事务在此快照上运行,直到事务结束。
MVCC:
以可重复读来举例的话,使用了MVCC的无锁机制
以操作1 insert了该条记录并提交
为例;
| id(事务id) | balance(修改的数据) | DB_ID(维护该条记录的id) | 上次修改的数据的地址 |
| 1 | 1000 | 1 | null |
在执行了更新操作20后,会插入数据
那么新的记录的这一栏 (上次修改的数据的地址)会保存上条快照的地址
| id(事务id) | balance(修改的数据) | DB_ID(维护该条记录的id) | 上次修改的数据的地址 |
| 20 | 500 | 20 | 0X0000007(假设其地址为) |
0X0000007存储的就是老数据的地址,如果操作需要回滚就会回滚到老数据的位置
此时操作20没有提交,与此同时,操作21查询了事务,那么此时
| 当前事务 | 未提交事务 | 未开始事务 |
| 21 | 20 21 | 22 |
已经产生的记录:注意读数据并不产生记录
| id(事务id) | balance(修改的数据) | DB_ID(维护该条记录的id) | 上次修改的数据的地址 |
| 20 | 500 | 20 | 0X0000007(假设其地址为) |
此时需要判断20是否小于未提交事务的最小序号,
如果小于,那么也就是说该事务已经提交,可以查询该记录,很显然20并不小于20,也就是说20这条记录并没有被提交,那么就会根据如下这一行定位到上一条记录
| 上次修改的数据的地址 |
| 0X0000007(假设其地址为) |
直到寻找该单元格的值小于20的记录,也就是找到已经提交的记录
| DB_ID(维护该条记录的id) |
| 20 |
在例子中是这行数据,来读取已经提交事务的值
| id(事务id) | balance(修改的数据) | DB_ID(维护该条记录的id) | 上次修改的数据的地址 |
| 1 | 1000 | 1 | null |
这就是MVCC的事务隔离机制
更多推荐
所有评论(0)