事务特性
https://blog.csdn.net/zxcyxg123/article/details/132020499
MVCC
MVCC(Multi-Version Concurrency Control),即多版本并发控制,是一种并发控制的方法,主要用于数据库管理系统中,以实现对数据库的并发访问。以下是对MVCC的详细解释:
-
目的:MVCC的主要目的是允许多个用户同时访问数据库,而不会导致数据冲突和不一致性。它通过在系统中维护多个版本的数据来实现这一目的。
-
工作原理:
-
优点:
-
使用场景:
-
实现方式:不同的数据库系统对MVCC的实现方式可能有所不同。例如,在MySQL的InnoDB存储引擎中,MVCC(多版本并发控制)的实现方式独特而高效。InnoDB通过为每一行记录添加两个额外的隐藏字段来实现MVCC,这两个字段并不直接存储数据被创建或删除的实际时间,而是存储了与这些事件相关联的系统版本号(通常称为“trx_id”和“roll_ptr”)。
“trx_id”字段用于表示最近一次修改该行记录的事务ID。每当一个事务修改某一行数据时,该行的“trx_id”字段就会被更新为该事务的ID。
“roll_ptr”字段是一个指向回滚段(undo log)中旧版本数据的指针。当事务修改数据时,旧的数据版本会被保存在回滚段中,并通过“roll_ptr”与新版本的数据相关联。这样,其他事务在需要读取该行数据的旧版本时,就可以通过“roll_ptr”找到相应的回滚段记录。
通过这种方式,InnoDB能够同时支持多个事务并发访问同一行数据,而无需进行加锁操作。每个事务都可以读取到该行数据的一个“快照”,这个“快照”是该事务开始时刻该行数据的版本。即使其他事务在此期间修改了该行数据,也不会影响到当前事务读取的数据版本。
例子
老袁的账户余额100元,老张转了100元给老袁,老袁消费了50元,同时发生
Oracle
默认隔离级别:读已提交
事务A | 事务B |
开启事务 | 开启事务 |
select balance from user_account where user_name = 'oldYuan';// 100 | select balance from user_account where user_name = 'oldYuan';// 100 |
update user_account set balance = balance + 100 where user_name = 'oldYuan';// 200 | |
select balance from user_account where user_name = 'oldYuan';// 100 | |
提交事务 | |
select balance from user_account where user_name = 'oldYuan';// 200 | |
提交事务 |
看这个例子(错误)
事务A | 事务B |
开启事务 | 开启事务 |
select balance from user_account where user_name = 'oldYuan';// 100 | select balance from user_account where user_name = 'oldYuan';// 100 |
update user_account set balance = balance + 100 where user_name = 'oldYuan';// 200 | |
update user_account set balance = balance - 50 where user_name = 'oldYuan';// 50 | |
提交事务 | |
select balance from user_account where user_name = 'oldYuan';// 200 | |
提交事务 | |
select balance from user_account where user_name = 'oldYuan';// 50 |
正确的如下
事务A | 事务B |
开启事务 | 开启事务 |
select balance from user_account where user_name = 'oldYuan';// 100 | select balance from user_account where user_name = 'oldYuan';// 100 |
update user_account set balance = balance + 100 where user_name = 'oldYuan';// 200 写锁 | |
select balance from user_account where user_name = 'oldYuan';// 100 | |
update user_account set balance = balance - 50 where user_name = 'oldYuan';// 阻塞 | |
提交事务 释放写锁 | …… |
update user_account set balance = balance - 50 where user_name = 'oldYuan';// 200 - 50 = 150 | |
提交事务 |
MySql
默认隔离级别:可重复读
事务A | 事务B |
开启事务 | 开启事务 |
select balance from user_account where user_name = 'oldYuan';// 100 | select balance from user_account where user_name = 'oldYuan';// 100 |
update user_account set balance = balance + 100 where user_name = 'oldYuan';// 200 | |
提交事务 | |
select balance from user_account where user_name = 'oldYuan';// 100 | |
提交事务 |
看这个例子(错误)
事务A | 事务B |
开启事务 | 开启事务 |
select balance from user_account where user_name = 'oldYuan';// 100 | select balance from user_account where user_name = 'oldYuan';// 100 |
update user_account set balance = balance + 100 where user_name = 'oldYuan';// 200 | |
提交事务 | |
select balance from user_account where user_name = 'oldYuan';// 100 | |
update user_account set balance = balance - 50 where user_name = 'oldYuan'; // 100 - 50 = 50? | |
提交事务 |
正确如下
事务A | 事务B |
开启事务 | 开启事务 |
select balance from user_account where user_name = 'oldYuan';// 100 | select balance from user_account where user_name = 'oldYuan';// 100 |
update user_account set balance = balance + 100 where user_name = 'oldYuan';// 200 | |
提交事务 | |
select balance from user_account where user_name = 'oldYuan';// 100 | |
update user_account set balance = balance - 50 where user_name = 'oldYuan';// update执行时,会使用最新版本的数据,结果是150,正确 | |
提交事务 |
数据库锁
在数据库中,排他锁(Exclusive Lock)和共享锁(Shared Lock)是两种常见的锁类型,它们用于控制多个事务对同一资源的并发访问,以保证数据的一致性和完整性。
一、排他锁(Exclusive Lock)
排他锁,又称为写锁或独占锁,是一种基本的锁类型。当某个事务对数据对象(如表、行等)加上排他锁后,其他事务将无法再对该数据对象加任何类型的锁,直到持有排他锁的事务释放该锁。这就意味着持有排他锁的事务在锁释放前可以独占地读取和修改数据,而其他事务在此期间无法访问该数据。
排他锁的主要特点包括:
二、共享锁(Shared Lock)
共享锁,又称为读锁,是一种允许其他事务并发读取数据的锁类型。当某个事务对数据对象加上共享锁后,其他事务可以并发地读取该数据,但任何事务都不能获取数据上的排他锁,直到已释放所有共享锁。
共享锁的主要特点包括: