事务

20 分钟阅读 1489 字 + 2509 词
一、事务(==重要==)
1、概念
构成单一逻辑工作单元的操作集合,一组命令的集合。
2、事务的四大基本特征(==重要==)ACID
1、 原子性 A:事务中的操作, 要么全部都发生,要么全部都不发生
2、 一致性 C:事务的执行的前后,数据的完整性保持一致。 且事务执行前后数据的总和不变,或者说是保持同一个约束。
3、 隔离性 I:一个事务内部的操作及使用的数据对并发的其他事务是隔离的,并发执行的 各个事务之间不能互相干扰 。与隔离级别有关系。
4、 持久性 D:指一个事务一旦提交, 它对数据库中数据的改变就应该是永久性的
3、事务的基本操作
mysql
#开启事务
start transaction/begin;

#提交事务
commit

#回滚事务,回滚到初始状态或者回滚点
rollback (to sp1)

#回滚点
savepoint (sp1)

#删除回滚点
release savepoint
mysql
#显示表的创建过程(可以看到表的名字、表中字段、字段类型、表的存储引擎、字符集)
show create table member;

#查看数据库中某张表的数据的条数
select count(*) from user;
二、并发产生的四大问题(==重要==)
1、脏写
概念:脏写是指当多个事务并发 写同一数据 时,先执行的事务所写的数据会被后写的数据 覆盖
image-20230630114849828
2、脏读
如果一个事务A向数据库写数据,但该事务 还没提交或终止 ,另一个事务B就看到了事务A写入数据库的数据,这个现象我们称为脏读
image-20230630143209624
3、不可重复读
一个事务有对同一个数据项的多次读取,但是在某前后两次读取之间,另一个事务更新该数据项,并且 提交 了。在后一次读取时, 感知到了提交的更新 。这个现象我们称为 不可重复读
image-20230630143843945
4、幻读
一个事务需要进行前后两次统计,在这两次统计期间,另一个事务 插入 了新的符合统计条件的记录,并且 提交 了。导致 前后两次统计的数据条数不一致
image-20230630144300870
三、隔离级别
四个隔离等级。== 读未提交 < 读已提交< 可重复读 < 可串行化。 ==
image-20230630145317362
1、读未提交
不能产生脏写,演示步骤如下
image-20230630150021155
可以产生脏读,演示方法如下:
左边会话没有提交的情况下,右边会话都可以读到更新的数据age = 30;
image-20230630150201050
可以产生不可重复读,演示如下:
左边会话将事务提交,然后右边会话发现第一次读的时候age = 50, 现在age = 30,前后两次读的时候,数据是不一样的。
image-20230630150336706
可以产生幻读,演示顺序:
image-20230630150808009
image-20230630150858162
2、读已提交
不可以产生脏写与脏读,但是可以产生不可重复读与幻读。
3、可重复读
可以避免脏写、脏读、不可重复读,但是可以产生幻读。(借助了主键唯一性的特点)
image-20230630152849553
image-20230630153029562
4、可串行化
脏写、脏读、不可重复读、幻读都可以避免。
image-20230630153416305
mysql
#查看当前事务的隔离级别
select @@session.transaction_isolation;
select @@tx_isolation;

#查询当前隔离级别
select @@session.transaction_isolation;

#设置当前隔离级别为读未提交
set session transaction isolation level read uncommitted;

#设置当前隔离级别为读已提交
set session transaction isolation level read committed;

#设置当前隔离级别为可重复读
set session transaction isolation level repeatable read;

#设置当前隔离级别为可串行化
set session transaction isolation level serializable;
事务隔离级别实现原理是什么?
mysql利用 MVCC无锁机制
数据库表中除了原数据的这些列以外,还维护了3个我们看不到的隐藏列
DB_TRX_ID 当前这条数据被哪个事务维护了
DB_ROLL_PTR 存储这条新数据的老数据的指针 ,一旦需要更新的操作需要回滚,就会利用这个指针来进行数据回滚, 这些历史数据存在了undolog里面,以链表的方式进行存储
在没有维护主键ID的时候,会维护一个ROW_ID的隐藏列。利用这个来建主键索引
创建一个readview快照信息,再通过这个readview去找undolog里的每一条信息。按规则一个个找。
MVCC就是乐观锁的一种体现
读未提交 无需锁无需MVCC, 因为修改数据改源数据,会出现脏读
读已提交 每次查询都会创建Readview读取数据
可重复读 同样的查询只会第一次创建Readview快照
串行化 直接使用的表锁,或者是读写锁
对于「读提交」和「可重复读」隔离级别的事务来说,它们是通过 Read View 来实现的,它们的区别在于创建 Read View 的时机不同,大家可以把 Read View 理解成一个数据快照,就像相机拍照那样,定格某一时刻的风景。「读提交」隔离级别是在「每个语句执行前」都会重新生成一个 Read View,而**「可重复读」隔离级别是「启动事务时」生成一个 Read View,然后整个事务期间都在用这个 Read View**
总结
1、MySQL 支持4种隔离级别, 默认为 RR (repeatable read) ,Oracle 只支持 read committed 和 serializable 两种隔离级别,默认为 read committed.
2、随着隔离等级的提高,并发程度是越来越低的,并发产生的问题是越来越少的。隔离级别越低,并发程度越高,产生的问题越多。