是在 MySQL 绿色版 8.0.25下测试学习的
事务
为什么使用事务
理解:
为了解决一些并发的业务或者解决需要一组sql语句组合才能成为一个完整的逻辑工作处理单元的操作(实现功能)。比如最经典的转账业务,一个人卡上账户余额减少一定的金额,同时被转账的那个人的余额增加相应的金额。
什么是事务
1.概念:
构成单一逻辑工作单元的操作集合称作事务(transaction),它是作为不可分割的逻辑单元执行的一组sql语句。
2.具体理解事务:
场景:
转账:杨过给小龙女转账5000,杨过的账户减少5000,小龙女的账户上增加5000。
代码
## 设存在 t_accounts 表,其中存在两个账户 【卡号,户主,余额】
id card_no name balance
1 123666321 杨某 20000
2 456888654 龙某 10000
##
#0、开启事务
begin ;
#1、杨某 账户上减少 5000
UPDATE t_accounts SET balance = balance - 5000 WHERE card_no = '123666321' ;
#2、龙某 账户上增加 5000
UPDATE t_accounts SET balance = balance + 5000 WHERE card_no = '456888654' ;
#3、提交事务
commit ;
3.连接、会话的理解:
连接(connection):客户端程序(Java、C、js、命令提示符界面连接MySQL服务、Navicat客户端等等)与MySQL服务之间构建联接。成功之后,就可以算一次会话,就可以操作MySQL服务了。
会话(session):一次连接成功就可以算一个会话,一个会话可以发生许多事务(Transtaction)。
事务的特性
Atomicity(原子性)
事务中所有特性要么都发生,要么都不发生。(事务操作做了一半由于一些因素后面的操作发生不了,则撤销之前成功的操作,恢复到没有发生事务操作的状态)
Consistency(一致性)
事务将数据库从一种一致状态转变为下一组一致状态
Isolation(隔离性)
事务和事务之间是彼此独立隔离的。
Durability(持久性)
事务一旦提交,其结果就是持久的。
事务代码流程
下面步骤是在MySQL命令行下进行的操作:
## 连接MySQL服务 --> 一个会话 -->已经开启了一个自动提交的事务(隐式开启)
# 1.在当前会话中自主控制事务的提交与回滚,需要关闭系统自动提交事务的变量值。
SET @@autocommit = 0; # 系统变量@@autocommit 默认 是 1 ,系统自动提交事务 改为0 人为手动提交事务
# 2.一组sql语句操作
DML语句【INSERT, UPDATE, DELETE】等
# 3.回滚(撤销事务中的所有操作)
rollback;
# 4.提交事务(意味着终结该事务)
commit;
## 在同一个会话中 一旦提交一个事务 则会开启一个新的事务
事务控制语句
1) 事务 SQL 控制语句
• START TRANSACTION (或 BEGIN )
:显式开始一个新事务
• SAVEPOINT
:分配事务过程中的一个位置,以供将来引用
• COMMIT
:永久记录当前事务所做的更改
• ROLLBACK
:取消当前事务所做的更改
• ROLLBACK TO SAVEPOINT
:取消在 savepoint 之后执行的更改
• RELEASE SAVEPOINT
:删除 savepoint 标识符
• SET AUTOCOMMIT
:为当前连接禁用或启用默认 autocommit 模式
2)autocommit 模式:
如何设置 AUTOCOMMIT
模式决定了如何以及何时开始新事务。默认情况下, AUTOCOMMIT
处于全局启用状态,这意味着会强制每个 SQL 语句隐式开始一个新事务。可以通过一个选项文件全局禁用 AUTOCOMMIT ,也可以通过设置 autocommit 变量为每个会话禁用它 set @@autocommit = 0;
。
启用 AUTOCOMMIT
会限制每个语句,并进而影响其自身事务中的事务表。这样可以有效地防止在一个事务中执行多个语句。这意味着,您将无法通过 COMMIT 或 ROLLBACK 作为一个单元提交或回滚多个语句。有时,会将这种情况误认为根本没有事务。但是,情况并非如此。启用 AUTOCOMMIT 后,每个语句仍会以原子方式执行。例如,通过在插入多个行时比较违反约束限制的效果,便可看出启用 AUTOCOMMIT 和根本不具有事务之间的差别。在非事务表(如 MyISAM )中,一旦发生错误,语句就会终止,已经插入的行会保留在该表中。而对于 InnoDB 表,已经插入的所有行都会从该表中删除,从而不会产生任何实际影响。
AUTOCOMMIT
确定开始新事务的方式和时间;默认情况下, AUTOCOMMIT
模式处于启用状态:作为一个事务隐式提交每个语句;
使用 SELECT 检查 AUTOCOMMIT 设置:为1是自动提交模式,0是手动提交模式。
SELECT @@AUTOCOMMIT;
3) 隐式提交:
COMMIT
语句始终会 显式提交
当前事务。其他事务控制语句 还具有隐式提交当前事务的作用。DDL语句等
除了这些事务控制语句之外,其他类型的语句可能也具有隐式提交并进而终止)当前事务的作用。这些语句的行为就像在执行实际语句之前发出 COMMIT 一样。此外,这些语句本身并非事务语句,也就是说,如果成功,则无法回滚。通常,数据定义语句、据访问和用户管理语句以及锁定语句
具有这种效果。
隐式提交 会终止当前事务。用于隐式提交的 SQL 语句:
START TRANSACTION
SET AUTOCOMMIT = 1
导致提交的非事务语句:
数据定义语句( ALTER 、 CREATE 和 DROP )
管理语句( GRANT 、 REVOKE 和 SET PASSWORD )
锁定语句( LOCK TABLES 和 UNLOCK TABLES )
导致隐式提交的语句示例:
Mysql>TRUNCATE TABLE
Mysql>LOAD DATA INFILE
多事务并发
多事务并发可能发生的问题与相应的简单解决方案
1.Lost Update 更新丢失:
a. 第一类更新丢失,回滚覆盖:撤消一个事务时,在该事务内的写操作要回滚,把其它已提交的事务写入的数据覆盖了。
b. 第二类更新丢失,提交覆盖:提交一个事务时,写操作依赖于事务内读到的数据,读发生在其他事务提交前,写发生在其他事务提交后,把其他已提交的事务写入的数据覆盖了。这是不可重复读的特例。
解决第一类更新丢失:read uncommitted 即可
2.Dirty Read 脏读:
一个事务读到了另一个未提交的事务写的数据。
解决脏读:read committed 即可
3.Non-Repeatable Read 不可重复读:
一个事务中两次读同一行数据,可是这两次读到的数据不一样。
解决不可重复读:repeatable read 即可
4.Phantom Read 幻读:
一个事务中两次查询,但第二次查询比第一次查询多了或少了几行或几列数据。
解决幻读:serialization 可串行化
事务隔离级别
为了解决多个事务并发会引发的问题,进行并发控制。数据库系统提供 了四种事务隔离级别供用户选择。
Read Uncommitted 读未提交:
不允许第一类更新丢失。允许脏读,不隔离事务。
Read Committed 读已提交:
不允许脏读,允许不可重复读。
Repeatable Read 可重复读:
不允许不可重复读。但可能出现幻读。
Serializable 串行化:
所有的增删改查串行执行。