MySQL(8-事务)
基本介绍
数据库中的事务是指对数据库执行一批操作,在同一个事务当中,这些操作最终要么全部执行成功,要么全部失败,不会存在部分成功的情况。
- 事务是一个原子操作,是一个最小执行单元,可以由一个或多个 SQL 语句组成
 - 在同一个事务当中,所有的 SQL 语句都成功执行时整个事务成功,有一个 SQL 语句执行失败时整个事务都执行失败。
 
使用案例
比如 A 用户给 B 用户转账 100 操作,过程如下:
- 从 A 账户扣 100
 - 给 B 账户加 100
 
如果在事务的支持下,上面最终只有 2 种结果:
- 操作成功:A 账户减少 100;B 账户增加 100
 - 操作失败:A、B 两个账户都没有发生变化
 
四大特征
- 原子性:是不可分割的最小操作单位,要么同时成功,要么同时失败
 - 持久性:当事务提交或回滚后,数据库会持久化的保持数据
 - 隔离性:多个事务之间相互独立,一个事务的执行不能被其他事务干扰
 - 一致性:事务操作前后,数据总量不变
 
事务操作
分类
mysql 中事务默认是隐式事务,执行 insert、update、delete 操作的时候,数据库自动开启事务、提交或回滚事务。是否开启隐式事务是由变量 autocommit 控制的,所以事务分为隐式事务和显式事务。
- 隐式事务
 
事务自动开启、提交或回滚,比如 insert、update、delete 语句,事务的开启、提交或回滚由 mysql 内部自动控制的。
查看变量 autocommit 是否开启了自动提交:show variables like ‘autocommit’;
- 显式事务
 
事务需要手动开启、提交或回滚,由开发者自己控制。
1  | -- 方式1:设置不自动提交事务  | 
语法
- 开启事务:start transaction
 - 回滚:rollback
 - 提交:commit
 - 事务提交的两种方式:
 
- 自动提交:MySQL 是自动提交的,一条 DML(增删改)语句会自动提交一次事务
 - 手动提交:Oracle 数据库默认是手动提交事务,需要先开启事务,再提交
 
修改事务的默认提交方式:
- 查看事务的默认提交方式:select @@autoncommit;(1 代表自动提交,0 代表手动提交)
 - 修改默认提交方式:set @@autocommit = 0;
 
- 部分回滚:savepoint
 - 只读事务:start transaction read only;
 
使用案例
- 事务提交
 
1  | mysql> select * from test1;  | 
- 事务部分回滚
 
1  | mysql> start transaction;  | 
- 只读事务
 
表示在事务中执行的是一些只读操作,如查询,但是不会做 insert、update、delete 操作,数据库内部对只读事务可能会有一些性能上的优化。
1  | mysql> commit;  | 
存在问题
多个事务之间隔离的,相互独立的,但是如果多个事务操作同一批数据,则会引发一些问题,设置不同的隔离级别就可以解决这些问题
- 脏读:一个事务,读取到另一个事务中没有提交的数据
 - 不可重复读(虚读):在同一个事务中,两个读取到的数据不一样
 - 幻读:一个事务操作(DML)数据表中所有记录,另一个事务添加了一个数据,则第一个事务查询不到自己的修改
 
隔离级别
分类
- read uncommitted:读未提交
 
产生的问题:脏读、不可重复读、幻读
| 时间 | 窗口 A | 窗口 B | 
|---|---|---|
| T1 | start transaction; | 
|
| T2 | select * from test1; | 
|
| T3 | start transaction; | 
|
| T4 | insert into test1 values (1); | 
|
| T5 | select * from test1; | 
|
| T6 | select * from test1; | 
|
| T7 | commit; | 
|
| T8 | commit; | 
- read committed:读已提交(Oracle)
 
产生的问题:不可重复读、幻读
| 时间 | 窗口 A | 窗口 B | 
|---|---|---|
| T1 | start transaction; | 
|
| T2 | select * from test1; | 
|
| T3 | start transaction; | 
|
| T4 | insert into test1 values (1); | 
|
| T5 | select * from test1; | 
|
| T6 | select * from test1; | 
|
| T7 | commit; | 
|
| T8 | select * from test1; | 
|
| T9 | commit; | 
- repeatable read:可重复读(MySQL 默认)
 
产生的问题:幻读
| 时间 | 窗口 A | 窗口 B | 
|---|---|---|
| T1 | start transaction; | 
|
| T2 | select * from test1; | 
|
| T3 | start transaction; | 
|
| T4 | insert into test1 values (1); | 
|
| T5 | select * from test1; | 
|
| T6 | select * from test1; | 
|
| T7 | commit; | 
|
| T8 | select * from test1; | 
|
| T9 | commit; | 
|
| T10 | select * from test1; | 
- serializable:串行化
 
可以解决所有的问题
注意:隔离级别从小到大安全性越来越高,但是效率越来越低
总结
| 隔离级别 | 脏读可能性 | 不可重复读可能性 | 幻读可能性 | 
|---|---|---|---|
| READ-UNCOMMITTED | 有 | 有 | 有 | 
| READ-COMMITTED | 无 | 有 | 有 | 
| REPEATABLE-READ | 无 | 无 | 有 | 
| SERIALIZABLE | 无 | 无 | 无 | 
相关命令
- 数据库查询隔离级别:
 
- select @@tx_isolation;
 - show variables like ‘transaction_isolation’;
 
- 数据库设置隔离级别:set global transaction isolation level 级别字符串;
 
本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来源 爱编程的小生!
 评论
