MySQL 事务和事务隔离

事务隔离:为什么你修改了我还看不见?

事务的基础知识

事务transaction:指一组SQL语句,通常一个事务对应一个完整的业务。
回退rollback:指撤销指定SQL语句的过程
提交commit:指将未存储的SQL语句结果写入数据库表

事务处理机制可以维持数据库的完整性 ,保证成批的MySQL操作要么完全执行,要么完全不执行

事务支持在引擎层实现,但并不是所有的引擎都支持事务,InnoDB支持事务

事务四大特性(ACID)

原子性(Atomicity):事务是最小单位,不可再分
一致性(Consistency):事务要求所有的DML(数据操作增删改)语句操作的时候,必须保证同时成功或者同时失败
隔离性(Isolation):同一时间,只允许一个事务请求同一数据,不同的事务之间彼此没有任何干扰。比如A正在从一张银行卡中取钱,在A取钱的过程结束前,B不能向这张卡转账。
持久性(Durability):事务完成后,事务对数据库的所有更新将被保存到数据库,不能回滚。

控制事务处理

事务的启动方式:BEGIN或START TRANSACTION :标识事务的开始,COMMIT和ROLLBACK语句执行后,事务会自动关闭。

修改默认行为

SET autocommit = FALSE(/0)关闭默认提交行为。

autocommit针对每个连接,而不是服务器

一般的Mysql语句都是直接针对数据库表执行和编写的,隐含提交。(DML可以修改默认提交行为)
在事务处理块中,提交需要指明。

区别 DDL DML
具体操作 create、表的管理 增删(delete)改
是否可以回滚 操作一旦执行,不可回滚,执行完DDL之后一定会执行一次COMMIT,且不受autocommit影响 默认情况下,一旦执行,不可回滚
如果在执行DML之前,修改默认提交行为SET autocommit = FALSE,则执行的DML操作就可以回滚

建议使用set autocommit=1

commit work and chain

对于一个需要频繁使用事务的业务,在 autocommit 为 1 的情况下,用 begin 显式启动的事务,如果执行 commit 则提交事务,再使用begin重新开启下一个事务。
如果执行 commit work and chain,则是提交事务并自动启动下一个事务,这样也省去了再次执行 begin 语句的开销。同时带来的好处是从程序开发的角度明确地知道每个语句是否处于事务中。

COMMIT与ROLLBACK

COMMIT:不出错时提交数据。一旦执行COMMIT,则数据被永久的保存在数据库中,该数据不可以回滚

ROLLBACK:回滚数据。一旦执行ROLLBACK,则可以实现数据的回滚(不一定成功),回滚到最近的一次COMMIT之后

使用保留点

设置保留点的目的是实现部分提交与回滚

创建保留点:SAVEPOINT 保留点

案例

START TRANSACTION;
DELETE FROM USER WHERE id = 1;
SAVEPOINT a;
DELETE FROM USER WHERE id = 2;
ROLLBACK TO a;

image

说明

保留点在事务处理完成后自动释放。也可以用RELEASE TRANSACTION 保留点明确释放保留点。没有指定保留点,会报异常。

隔离性与隔离级别

数据库有多个事物同时执行时,可能出现

  • 脏读 dirty read 某个事务已更新一份数据,另一个事务在此时读取了同一份数据,由于某些原因,前一个RollBack了操作,则后一个事务所读取的数据就会是不正确的
  • 不可重复读 non-repeatable read 在一个事务的两次查询之中数据不一致。
  • 幻读phantom read 系统管理员A将数据库中所有学生的成绩从具体分数改为ABCDE等级,但是系统管理员B就在这个时候插入了一条具体分数的记录,当系统管理员A改结束后发现还有一条记录没有改过来,就好像发生了幻觉一样,这就叫幻读。

不可重复读的和幻读很容易混淆,不可重复读侧重于修改,幻读侧重于新增或删除。解决不可重复读的问题只需锁住满足条件的行,解决幻读需要锁表

为了解决这些问题,提出了"隔离级别"

SQL 标准的事务隔离级别包括:

隔离级别 描述 避免脏读 避免不可重复读 避免幻读
读未提交(read uncommitted) 一个事务还没提交时,它做的变更就能被别的事务看到。 × × ×
读提交(read committed) 一个事务提交之后,它做的变更才会被其他事务看到。 × ×
可重复读(repeatable read) 事务在执行期间看到的数据前后必须是一致的。A事务无论执行多少次,只要不提交,B事务查询值都不变,B事务仅查询B事务开始时那一瞬间的数据快照。(MySQL8默认隔离级别) ×
串行化(serializable ) 对于同一行记录,“写”会加“写锁”,“读”会加“读锁”。当出现读写锁冲突(读读不冲突)的时候,后访问的事务必须等前一个事务执行完成,才能继续执行。

隔离级别案例理解

create table T(c int) engine=InnoDB;
insert into T(c) values(1);

假设数据表 T 中只有一列,其中一行的值为 1,下面是按照时间顺序执行两个事务的行为。

事物A 事物B 读未提交 读提交 可重复读 串行化
启动事物,查询得到值1 启动事物 此行被事物A加锁

查询得到值1

将1修改到2 这里被事物A加锁了,只有等事物A执行完毕,才可以执行
查询得到值V1 2 1 1 1

提交事务B
查询得到值V2 2 2 1
事务在执行期间看到的数据前后必须是一致的
1
提交事物A
查询得到值V3 2 2 2 2

在实现上,数据库里面会创建一个视图,访问的时候以视图的逻辑结果为准。

隔离级别 视图实现
读未提交 直接返回记录上的最新值,没有视图概念
读提交 视图是在每个SQL语句开始执行的时候创建的
可重复读 视图在事务启动时创建的,可以看作视图是静态的,整个事务存在期间都用这个视图。
这样才可以保证执行期间读到的数据一致。
串行化 直接用加锁的方式来避免并行访问。

隔离级别的设置

Oracle 数据库的默认隔离级别是“读提交”,因此对于一些从 Oracle 迁移到 MySQL 的应用,为保证数据库隔离级别的一致,一定要将 MySQL 的隔离级别设置为“读提交”。

transaction-isolation参数

语法:set 作用域 transaction isolation level 事务隔离级别

说明
1.若没有输入作用域直接修改transaction isolation,显示修改成功,但实际上没有修改!
2.设置本次会话session的事务隔离级别,只在本会话有效,不会影响到其它会话
3.设置全局global的事务隔离级别,该设置不会影响当前已经连接的会话,设置完毕后,新打开的会话,将使用新设置的事务隔离级别

# 查看mysql的隔离级别:可重复读REPEATABLE-READ
mysql> show variables like 'transaction_isolation';
+-----------------------+-----------------+
| Variable_name         | Value           |
+-----------------------+-----------------+
| transaction_isolation | REPEATABLE-READ |
+-----------------------+-----------------+
1 row in set (0.02 sec)
# 使用Mysql查询
mysql> select @@transaction_isolation;
+-------------------------+
| @@transaction_isolation |
+-------------------------+
| REPEATABLE-READ         |
+-------------------------+
1 row in set (0.00 sec)


# 设置本次会话为读提交READ-COMMITTED,仅在本次会话有效,不影响其他会话,
mysql> set session transaction isolation level read committed;
mysql>  select @@transaction_isolation;
+-------------------------+
| @@transaction_isolation |
+-------------------------+
| READ-COMMITTED          |
+-------------------------+
1 row in set (0.00 sec)

# 设置全局的事务隔离级别,该设置不会影响当前已经连接的会话,设置完毕后,新打开的会话,将使用新设置的事务隔离级别
mysql> set global transaction isolation level repeatable read;
Query OK, 0 rows affected (0.00 sec)
mysql>  select @@transaction_isolation;
+-------------------------+
| @@transaction_isolation |
+-------------------------+
| READ-COMMITTED          |
+-------------------------+
1 row in set (0.00 sec)

事务隔离的实现

用MVCC机制实现事务隔离

后续学习到了补充

如何避免长事务对业务的影响?

posted @ 2022-01-02 20:37  rananie  阅读(73)  评论(0编辑  收藏  举报