目录
- 一、前言
- 二、本文章目标
- 三、什么是事务?
- 四、事务的ACID特性
- 五、为什么要使用事务
- 六、如何使用事务
- 6.1 查看支持使用事务的引擎
- 6.2语法
- 6.3 开启⼀个事务,执行更新后回滚
- 6.4 开启一个事务更新后提交
- 6.5 保存点
- 6.6 自动/手动提交事务
- 七、事务的隔离性和隔离级别
- 7.1什么是隔离性
- 7.2隔离级别
- 7.2.1 四种隔离级别在现实生活和在事务中的场景:
- 7.3查看和设置隔离级别
- 7.4不同隔离级别的性能与安全
一、前言
欢迎大家来到权权的博客~ 欢迎大家对我的博客进行指导,有什么不对的地方,我会及时改进哦~
博客主页链接点这里–>:权权的博客主页链接
二、本文章目标
了解事务的概念与使⽤场景
掌握事务的ACID特性
掌握如何使用事务
掌握事务的隔离性与隔离级别
三、什么是事务?
事务把⼀组SQL语句打包成为⼀个整体,在这组SQL的执行过程中,要么全部成功,要么全部失败。这组SQL语句可以是⼀条也可以是多条。
来看一个转转账的例子:
--------------- 创建账户表 --------------
create table if not exists account
(
ID bigint(11) primary key auto_increment,
name varchar(25) not null,
balance decimal(10,2)
)engine=innodb;
----------- 插入数据 ---------------
INSERT INTO account(name,balance) VALUES('小肖',200.00);
INSERT INTO account(name,balance) VALUES('小王',400.00);
-------------- 更新数据 --------------
UPDATE account SET balance=balance-100 WHERE NAME='小肖';
UPDATE account SET balance=balance+100 WHERE NAME='小王';
• 如果转账成功,应该有以下结果:
- 小肖的账户余额减少 100 ,变成 100,小王的账户余额增加了 100 ,变成 500 ,不能出现小肖的余额减少而小王的余额没有增加的情况;
- 小肖和小王在发生转账前后的总额不变,也就是说转账前小肖和小王的余额总数为
200+400=600 ,转账后他们的余额总数为 100+500=600 ; - 转账后的余额结果应当保存到存储介质中,以便以后读取;
- 还有⼀点需要要注意,在转账的处理过程中小肖和小王的余额不能因其他的转账事件而受到干扰。
5.以上这四点在事务的整个执行过程中必须要得到保证,这也就是事务的 ACID 特性。
四、事务的ACID特性
事务的ACID特性指的是 Atomicity (原子性), Consistency (一致性), Isolation (隔离
性)和 Durability (持久性)。
• Atomicity (原子性):⼀个事务中的所有操作,要么全部成功,要么全部失败,不会出现只执行了⼀半的情况,如果事务在执行过程中发生错误,会回滚( Rollback )到事务开始前的状态,就像这个事务从来没有执行过⼀样;
• Consistency (⼀致性):在事务开始之前和事务结束以后,数据库的完整性不会被破坏。这表示写⼊的数据必须完全符合所有的预设规则,包括数据的精度、关联性以及关于事务z执行过程中服务器崩溃后如何恢复;
• Isolation (隔离性):数据库允许多个并发事务同时对数据进行读写和修改,隔离性可以防止多个事务并发执行时由于交叉执行而导致数据的不⼀致。事务可以指定不同的隔离级别,以权衡在不同的应用场景下数据库性能和安全;
• Durability (持久性):事务处理结束后,对数据的修改将永久的写入存储介质,即便系统故障也不会丢失。
五、为什么要使用事务
事务具备的ACID特性,是我们使⽤事务的原因,在我们日常的业务场景中有⼤量的需求要用事务来保证。支持事务的数据库能够简化我们的编程模型, 不需要我们去考虑各种各样的潜在错误和并发问题,在使用事务过程中,要么提交,要么回滚,不用去考考虑络异常,服务器宕机等其他因素,因此我们经常接触的事务本质上是数据库对 ACID 模型的⼀个实现,是为应用层服务的。
在使用数据库的过程中,对于修改只要提交成功,就可以安全的保存,只要回滚就可以恢复到事务之初。
六、如何使用事务
6.1 查看支持使用事务的引擎
要使⽤事务那么数据库就要⽀持事务,在MySQL中⽀持事务的存储引擎是InnoDB。
语法:
show engines;
6.2语法
# 开始⼀个新的事务
START TRANSACTION;
# 或
BEGIN;
# 提交当前事务,并对更改持久化保存
COMMIT;
# 回滚当前事务,取消其更改
ROLLBACK;
• START TRANSACTION 或 BEGIN 开始⼀个新的事务;
• COMMIT 提交当前事务,并对更改持久化保存;
• ROLLBACK 回滚当前事务,取消其更改;
• 无论提交还是回滚,事务都会关闭
6.3 开启⼀个事务,执行更新后回滚
6.4 开启一个事务更新后提交
6.5 保存点
在事务执⾏的过程中设置保存点,回滚时指定保存点可以把数据恢复到保存点的状态。
语法:
savepoint name
开启事务
更新小肖和小王的数据
数据已经更新
设置保存点1
继续更新小王跟小肖的数据
查看更新后的数据
设置保存点2
继续更新account表中的数据插入一个数据并且查看更新后的数据
回滚到保存点2,并且查看回滚之后的数据,可以看到与前面设置的保存点2数据一致,说明回滚成功。
回滚到保存点1,并且查看回滚之后的数据,可以看到与前面设置的保存点2数据一致,说明回滚成功
回滚时不指定保存点,直接回滚到事务开始时的原态,事务关闭。
6.6 自动/手动提交事务
默认情况下,MySQL是自动提交事务的,就是说我们执行的每个修改操作,比如插⼊、更新和删除,都会自动开启⼀个事务并在语句执行完成之后⾃动提交,发生异常时自动回滚。
查看当前事务是否自动提交可以使用以下语句:
show variables like 'autocommit';
• 可以通过以下语句设置事务为⾃动或⼿动提交
# 设置事务⾃动提交
SET AUTOCOMMIT=1; # ⽅式⼀
SET AUTOCOMMIT=ON; # ⽅式⼆
# 设置事务⼿动提交
SET AUTOCOMMIT=0; # ⽅式⼀
SET AUTOCOMMIT=OFF; # ⽅式⼆
注意:
只要使用 START TRANSACTION 或 BEGIN 开启事务,必须要通过 COMMIT 提交才会持久化,与是否设置 SET autocommit 无关。
• 手动提交模式下,不用显⽰开启事务,执行修改操作后,提交或回滚事务时直接使用 commit或 rollback。
• 已提交的事务不能回滚。
七、事务的隔离性和隔离级别
7.1什么是隔离性
MySQL服务可以同时被多个客户端访问,每个客户端执行的DML(GURD)语句以事务为基本单位,那么不同的客户端在对同⼀张表中的同⼀条数据进行修改的时候就可能出现相互影响的情况,为了保证不同的事务之间在执行的过程中不受影响,那么事务之间就需要要相互隔离,这种特性就是隔离性。
7.2隔离级别
事务具有隔离性,那么如何实现事务之间的隔离?隔离到什么程度?如何保证数据安全的同时也要兼顾性能?这都是要思考的问题。事务间不同程度的隔离,称为事务的隔离级别。
不同的隔离级别在性能和安全方面做了取舍,有的隔离级别注重并发性,有的注重安全性,有的则是并发和安全适中;在MySQL的InnoDB引擎中事务的隔离级别有四种,分别是:
• READ UNCOMMITTED,读未提交
• READ COMMITTED ,读已提交
• REPEATABLE READ ,可重复读(默认)
• SERIALIZABLE ,串行化
7.2.1 四种隔离级别在现实生活和在事务中的场景:
• READ UNCOMMITTED,读未提交
在机房上课时,我用我的U盘去拷贝一份老师上课的MySQL课件,这时老师在把课件分享到我们机房每个电脑上面,然后我发现我拷贝老师的MySQL课件跟老师分享出来的不一样,也就是说我拿到的是老师还没有提交的课件。
对应到事务中,事务A对数据进行了修改,事务B拿到了事务A还没有提交的数据,这个情况叫做“脏读”,事务B访问了事务A,rollback的数据。
• READ COMMITTED ,读已提交
我在看这个老师分享出来的MySQL课件的时候,老师突然对这个MySQL课件进行了修改,然后重新分享给我们,然后我一刷新,发现这个第一次看到的内容跟第二次看到的内容不一样。
事务A第一次查询到了某一条记录,此事务B对这条记录进行了修改并且提交了,当事务A再次查询这条记录的时候,发现与第一次查询结果不一样,这种现象叫做”不可重复读“。
• REPEATABLE READ ,可重复读(默认)
我在看课件的时候,叫老师不要修改这个课件,然后相当于给这个课件家里一把锁,但是对于其他课件的增加和删除,都是可以的,然后我当时看这个MySQL大课件下面有两个小课件,然后我点进一个小课件去看的时候,然后这个时候老师在MySQL课件下增加了一个小课件,然后我再重新看的时候,发现这个MySQL大课件下面多了一个课件。
事务A第一次查询了某给结果集,那么以相同的查询得到的结果集不一样与第一次不同,这个现象叫做“幻读”。(两次同样的查询得到的结果集不同)InooDB 存储引擎中,使用了next-key锁,锁住了目标与行之间的间隙,解决了部分的幻读问题。
• SERIALIZABLE ,串行化
解决了所有的数据安全问题,所有事务都是一个挨一个的执行,一个事务必须等到上一个事务执行完才执行。
7.3查看和设置隔离级别
• 事务的隔离级别分为全局作用域和会话作用域。
查看不同作用域事务的隔离级别,可以使用以下的方式:
# 全局作⽤域
SELECT @@GLOBAL.transaction_isolation;
# 会话作⽤域
SELECT @@SESSION.transaction_isolation;
设置事务的隔离级别和访问模式,可以使用以下语法:
#通过GLOBAL|SESSION分别指定不同作⽤域的事务隔离级别
SET [GLOBAL|SESSION] TRANSACTION ISOLATION LEVEL level|access_mode;
# 隔离级别
level: {
REPEATABLE READ # 可重复读
| READ COMMITTED # 读已提交
| READ UNCOMMITTED # 读未提交
| SERIALIZABLE # 串⾏化
}
# 访问模式
access_mode: {
READ WRITE # 表⽰事务可以对数据进⾏读写
| READ ONLY # 表⽰事务是只读,不能对数据进⾏读写
}
# ⽰例
# 设置全局事务隔离级别为串⾏化,后续所有事务⽣效,不影响当前事务
SET GLOBAL TRANSACTION ISOLATION LEVEL SERIALIZABLE;
# 设置会话事务隔离级别为串⾏化,当前会话后续的所有事务⽣效,不影响当前事务,可以在任何时候执⾏
SET SESSION TRANSACTION ISOLATION LEVEL SERIALIZABLE;
# 如果不指定任何作⽤域,设置只针对下⼀个事务,随后的事务恢复之前的隔离级别
SET TRANSACTION ISOLATION LEVEL SERIALIZABLE;
# ⽅式⼀
SET GLOBAL transaction_isolation = 'SERIALIZABLE';
# 注意使⽤SET语法时有空格要⽤"-"代替
SET SESSION transaction_isolation = 'REPEATABLE-READ';
# ⽅式⼆
SET @@GLOBAL.transaction_isolation='SERIALIZABLE';
# 注意使⽤SET语法时有空格要⽤"-"代替
SET @@SESSION.transaction_isolation='REPEATABLE=READ'
7.4不同隔离级别的性能与安全
欧耶!!!我学会啦!!!