【Mysql】第十一章 事务-重点(原子性+持久性+隔离性+一致性)



一、概念

事务由一条或多条SQL语句组成的一个整体,事务本质是能够简化我们的编程模型。

  • 原子性: 一个事务中的所有操作,要么全部完成,要么全部不完成,不会结束在中间某个环节。事务在执行过程中如果发生错误,则会自动回滚到事务开始前的状态,就像这个事务从来没有执行过一样。
  • 持久性: 事务处理结束后,对数据的修改就是永久的,即便系统故障也不会丢失。
  • 隔离性: 隔离性可以保证多个事务在并发执行时,不会因为由于交叉执行而导致数据的不一致。
  • 一致性: 在事务开始之前和事务结束以后,数据库的完整型没有被破坏。

原子性,持久性,隔离性是手段,一致性是目的

1.查看事务支持版本-show engines

show engines;

2.事务提交方式-show variables like ‘autocommit’

查看事务提交方式,ON表示打开自动提交,OFF表示关闭自动提交(开启手动提交)

show variables like 'autocommit';

设置事务的提交方式

set autocommit=0;//关闭自动提交.开启手动提交
set autocommit=1;//打开自动提交

3.事务常见操作方式

1.将mysql的默认隔离级别设置成读未提交,方便看到实验现象

set global transaction isolation level read uncommitted;

2.需要重启终端,进行查看隔离级别

quit退出重新登陆
select @@tx_isolation;

3.创建一个银行用户表

create table if not exists account(
id int primary key,
name varchar(50) not null default '',
blance decimal(10,2) not null default 0.0
)ENGINE=InnoDB DEFAULT CHARSET=UTF8;

4.演示 - 证明事务的开始与回滚

  • 使用begin 或 start transaction命令,可以启动一个事务。

  • 使用savepoint 保存点,可以在事务中创建指定名称的保存点。

  • 使用rollback to 保存点,可以让事务回滚到指定保存点。

  • 使用rollback命令,可以直接让事务回滚到最开始。

  • 使用commit命令,可以提交事务,提交事务后就不能回滚了。

start transaction;//启动一个事务或者begin
savepoint save1; //创建一个保存点save1
insert into account values (1, '张三', 100);//插入一条记录
savepoint save2;//创建一个保存点save2
insert into account values (2, '李四', 10000);//插入一条记录
rollback to save2; //回滚到保存点save2,此时表中只有张三的数据
rollback;//回滚在最开始,所有数据都没有了

5.演示原子性 - 证明未commit,客户端崩溃,MySQL自动会回滚

begin;//启动一个事务或者start transaction
insert into account values (1, '张三', 100);//插入一条记录
quit;//断开连接,mysql会自动让事务回滚到最开始,看不到任何记录

6.演示持久性-证明commit了,客户端崩溃,MySQL数据不会在受影响,已经持久化

begin;//启动一个事务或者start transaction
insert into account values (1, '张三', 100);//插入一条记录
commit;//提交事务
quit;//断开连接,仍然可以看到之前插入的记录

7.演示begin会自动更改提交方式为手动,不管autocommit是不是自动提交

//假如本来有张三的数据
set autocommit=1;//打开自动提交
begin;//启动一个事务或者start transaction
insert into account values (2, '李四', 10000);//插入一条记录
quit;//断开连接,mysql会自动让事务回滚到最开始,表中只有张三的数据

8.演示证明单条 SQL 与事务的关系

//假如本来有张三的数据
set autocommit=1;//打开自动提交
insert into account values (2, '李四', 10000);//插入一条记录
quit;//断开连接,mysql已经自动提交,表中有张三和李四两个人的数据

9.重要总结

  • 输入begin或者start transaction,事务便必须要通过commit提交,才会持久化,否则会回滚,与是否设置autocommit无关
  • 没用begin或者start transaction,只要设置autocommit=1(自动提交),退出会自动保存
  • 没用begin或者start transaction,只要设置autocommit=0(手动提交),必须要通过commit提交,才会持久化

二、事务的隔离级别

数据库为了保证事务执行过程中尽量不受干扰,于是出现了隔离性的概念

  • 读未提交(read uncommitted): 在该隔离级别下,所有的事务都可以看到其他事务没有提交的执行结果,实际生产中不可能使用这种隔离级别,因为这种隔离级别相当于没有任何隔离性,会存在很多并发问题,如脏读、幻读、不可重复读等。

  • 读提交(read committed): 该隔离级别是大多数数据库的默认隔离级别,但它不是MySQL默认的隔离级别,它满足了隔离的简单定义:一个事务只能看到其他已经提交的事务所做的改变,但这种隔离级别存在不可重复读和幻读的问题。

  • 可重复读(repeatable read): 这是MySQL默认的隔离级别,该隔离级别确保同一个事务在执行过程中,多次读取操作数据时会看到同样的数据,即解决了不可重复读的问题,但这种隔离级别下仍然存在幻读的问题。

  • 串行化(serializable): 这是事务的最高隔离级别,该隔离级别通过强制事务排序,使之不可能相互冲突,从而解决了幻读问题。它在每个读的数据行上面加上共享锁,但是可能会导致超时和锁竞争问题,这种隔离级别太极端,实际生成中基本不使用。

查看与设置隔离级别

查看全局隔离级别

select @@global.tx_isolation;

查看会话隔离级别

select @@tx_isolation;

设置会话隔离级别

set session transaction isolation level 隔离级别;

设置全局隔离级别

set global transaction isolation level 隔离级别;

读未提交-read uncommitted

左终端右终端
设置隔离性,并查看
set session transaction isolation level read uncommitted;
select @@tx_isolation;
设置隔离性,并查看
set session transaction isolation level read uncommitted;
select @@tx_isolation;
begin;//启动一个事务或者start transactionbegin;//启动一个事务或者start transaction
插入一条记录,此时没有提交,在右终端有数据
insert into account values (1, ‘张三’, 100);
select * from account;//表中没有数据
select * from account;//表中有数据

注意:一个事务在执行中,读到另一个执行中事务的更新但是未commit的数据,这种现象叫做脏读

读提交-read committed

左终端右终端
设置隔离性,并查看
set session transaction isolation level read committed;
select @@tx_isolation;
设置隔离性,并查看
set session transaction isolation level read committed;
select @@tx_isolation;
begin;//启动一个事务或者start transactionbegin;//启动一个事务或者start transaction
插入一条记录,此时没有提交,在右终端没有数据
insert into account values (1, ‘张三’, 100);
select * from account;//表中没有数据,创建read view
commit;//提交事务select * from account;//表中有数据,创建新read view

注意:一个事务在执行过程中,两个相同的select查询得到了不同的数据,这种现象叫做不可重复读,中间没用commit

在可重复读隔离级别下,一个事务在执行过程中,相同的select查询得到的是相同的数据,这就是所谓的可重复读

事务每次进行快照读时都会创建一个Read View(使用select),所以RC级别是不可重复读的

可重复读-repeatable read

左终端右终端
设置隔离性,并查看
set session transaction isolation level repeatable read;
select @@tx_isolation;
设置隔离性,并查看
set session transaction isolation level repeatable read;
select @@tx_isolation;
begin;//启动一个事务或者start transactionbegin;//启动一个事务或者start transaction
插入一条记录,此时没有提交,在右终端没有数据
insert into account values (1, ‘张三’, 100);
select * from account;//表中没有数据,创建read view
commit;//提交事务select * from account;//表中没有数据,使用之前的read view
commit;//提交事务
select * from account;//表中有数据,创建新read view

注意:一个事务在执行过程中,相同的select查询得到了新的数据,如同出现了幻觉,这种现象叫做幻读。中间用commit

事务在第一次快照会创建一个Read View(使用select)之后快照会使用最开始的Read View判断,所以之后的修改不可见,只会创建一次Read View,所以RR级别是可重复读的

串行化-serializable

左终端右终端
设置隔离性,并查看
set session transaction isolation level serializable;
select @@tx_isolation;
设置隔离性,并查看
set session transaction isolation level serializable;
select @@tx_isolation;
begin;//启动一个事务或者start transactionbegin;//启动一个事务或者start transaction
插入一条记录,此时没有提交,左终端被阻塞
insert into account values (1, ‘张三’, 100);
左终端被阻塞
当右终端commit后左终端insert才会提交commit;//提交事务

总结

隔离级别脏读不可重复读幻读加锁读
读未提交(read uncommitted)不加锁
读已提交(read committed)X不加锁
可重复读(repeatable read)XXX不加锁
可串行化(serializable)XXX加锁

三、一致性

  • 事务在执行中发生错误,则自动回滚到事务最开始的状态,即一致性需要原子性来保证。

  • 事务处理结束后,对数据的修改必须是永久的,即一致性需要持久性来保证。

  • 多个事务同时访问同一份数据时,必须保证这多个事务在并发执行时,不会因为由于交叉执行而导致数据的不一致,即一致性需要隔离性来保证。

四、多版本并发控制

多版本并发控制,要依赖记录中的3个隐藏字段、undo日志和Read View实现

记录中的3个隐藏字段

  • DB_TRX_ID:6字节,记录最近一次修改事务的ID。
  • DB_ROW_ID:6字节,隐含的自增ID(隐藏主键)。
  • DB_ROLL_PTR:7字节,回滚指针,指向这条记录的上一个版本。

image-20240804132128368

插入该记录的事务的事务ID为9,插入的第一条记录,DB_ROW_ID字段填的就是1,没有历史版本,所以回滚指针DB_ROLL_PTR的值设置为null

undo日志

undo log:回滚日志,是内存缓冲区。

快照

image-20240804143609992

原本undo缓冲区中只有ID为9的张三,现在插入一个李四,所以ID自增1,回滚指针指向张三,现在修改李四所以ID自增1,回滚指针只想原来的李四,undo log中的一个个的历史版本就称为一个个的快照。

Read View

录并维护系统当前活跃的事务ID,select时会生成read view


  • 13
    点赞
  • 15
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

penguin_bark

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值