目录
https://www.cnblogs.com/luchangyou/p/11321607.html
事务的四大特性(ACID)
1、原子性(Atomicity):原子性是指事务的不可分割,要么全部执行成功,要么全部失败,是一次完整的操作。
2、一致性(Consistency):一致性是指事务必须使数据库从一个一致性状态变换到另一个一致性状态,也就是说一个事务执行之前和执行之后都必须处于一致性状态。
3、隔离性(Isolation): 一个用户的事务不能被其它用户的事务所干扰,多个并发事务之间数据要相互隔离。
4、持久性(Durability):持久性是指一个事务一旦被提交了,那么对数据库中的数据的改变就是永久性的,即便是在数据库系统遇到故障的情况下也不会丢失提交事务的操作。
并发访问会导致的问题
如果不考虑隔离级别,事务会存在3种并发问题:
1)脏读:B事务读取到了A事务尚未提交的数据 ------ 要求B事务要读取A事务提交的数据
2)不可重复读:一个事务中两次读取的数据的内容不一致 ----- 要求的是一个事务中多次读取时数据是一致的 --- unpdate
3)幻读/虚读:一个事务中两次读取的数据的数量不一致 ----- 要求在一个事务多次读取的数据的数量是一致的 --insert delete
事务的隔离级别
1)read uncommitted : 读取尚未提交的数据 -> 哪个问题都不能解决
2)read committed:读取已经提交的数据 -> 可以解决脏读 ---- oracle、sql server、postgresql 默认的
3)repeatable read:重读读取 -> 可以解决脏读和不可重复读 ---mysql默认的
4)serializable:串行化 -> 可以解决脏读不可重复读和虚读---相当于锁表
mysql 如何实现 repeatable read 的?
通过MVCC机制+行锁,MVCC机制即多版本并发控制(multi-version concurrency control)。
通过保存数据在某个时间点的快照来实现的。不同存储引擎的MVCC实现是不同的,典型的有乐观并发控制和悲观并发控制。当我们创建表完成后,mysql会自动为每个表添加数据版本号(最后更新数据的事务id)db_trx_id 删除版本号 db_roll_pt (数据删除的事务id) 事务id由mysql数据库自动生成且递增,这两列内容是隐藏列。
MVCC 具体实现分析:
1. MVCC逻辑流程-插入(insert)
start transaction;(事务id为1) INSERT INTO user (name,sex) VALUES ('张三','男'); INSERT INTO user (name,sex) VALUES ('李四','男'); commit;
数据中对应表如下:
id | name | sex | db_trx_id | db_roll_pt |
1 | 张三 | 男 | 1 | null |
2 | 李四 | 男 | 1 | null |
2. MVCC逻辑流程-查询(select)
查询时需要同时满足以下两个条件:
1、查找数据版本号,早于(小于等于)当前事务id的数据行。 这样可以确保事务读取的数据是事务之前已经存在的。或者是当前事务插入或修改的。
2、查找删除版本号为 null 或者大于当前事务版本号的记录。 这样确保取出来的数据在当前事务开启之前没有被删除。
如下图,假如有一个事务中执行查询(假设事务id=2)
start transaction;(事务id为2) select * from user where sex = '男';
当刚创建完事务2,即将执行查询sql,
此时另一个事务 id=3 ,对表 user 进行插入:INSERT INTO user (name,sex) VALUES ('王五','男');并提交事务。数据中对应表如下:
id | name | sex | db_trx_id | db_roll_pt |
1 | 张三 | 男 | 1 | null |
2 | 李四 | 男 | 1 | null |
3 | 王五 | 男 | 3 | null |
事务id=2,查询的结果是两条数据,因为 id=2 要找小于等于2 的事务,并且删除版本号都为null。
3. MVCC逻辑流程-删除(delete)
标记删除,不是实际删除。
假如有一个事务中执行查询(假设事务id=4),
start transaction;(事务id为4)
select * from user where sex = '男';
此时另一个事务 id=5 ,对表 user 进行删除:DELETE FROM user WHERE id = 1;并提交事务。数据中对应表如下:
id | name | sex | db_trx_id | db_roll_pt |
1 | 张三 | 男 | 1 | 5 |
2 | 李四 | 男 | 1 | null |
3 | 王五 | 男 | 3 | null |
事务id=4,查询的结果是3条数据,因为 id=4 要找小于等于4 的事务,并且删除版本号都为null或大于id=4。
4. MVCC逻辑流程-修改(update)
当一个事务修改一条记录时, 要先复制该数据,新数据数据版本号为当前事务id,删除版本号为 null 。然后更新原来数据的删除版本号为当前事务id。如下:
假如一个事务 id=6 执行了一条update语句:UPDATE user SET name='李四2' WHERE id = 2;并提交事务。数据中对应表如下:
id | name | sex | db_trx_id | db_roll_pt |
1 | 张三 | 男 | 1 | 5 |
2 | 李四 | 男 | 1 | 6(复制数据到此表空间中) |
3 | 王五 | 男 | 3 | null |
4 | 李四2 | 男 | 6 | null |
事务id=4,查询的结果是3条数据,
mvcc 优缺点:
优点:在读取数据时,innodb几乎不用获取任何锁,在每个查询通过版本检查,只获取需要的数据版本,提高系统并发度;
缺点:为了实现多版本,innodb必须对每行增加相应字段来存储版本信息,同时需要维护每一行的版本信息,而且在检索行的时候,需要进行版本的比较,因而减低了查询效率;innodb还需要定期清理不再需要的行版本,及时回收空间,这也增加开销;