Loading

TCL

七、TCL

1 介绍

TCL:事务控制语言。

事物是由单独单元的一个或多个 SQL 语句组成,在这个单元中,每个 SQL 语句是相互依赖的。而整个单独单元作为一个不可分割的整体,如果单元中的某条 SQL 语句一旦执行失败或产生错误,整个单元将会回滚。所有受到影响的数据将返回到事务开始之前的状态;如果单元中的所有 SQL 语句都执行成功,则事务执行成功。

简单讲,事务指逻辑上的一组操作,组成这组操作的各个单元,要不全部成功,要不全部不成功。

事物的特点如下:

  • 原子性(A:atomicity): 事务是最小的执行单位,不允许分割。事务的原子性确保动作要么都执行,要么都回滚;
  • 一致性(C:consistency):执行事务前后,数据保持一致,多个事务对同一个数据读取的结果是相同的;
  • 隔离性(I:isolation): 并发访问数据库时,一个用户的事务不被其他事务所干扰,各并发事务之间数据库是独立的;
  • 持久性(D:durability): 一个事务被提交之后。它对数据库中数据的改变是持久的,即使数据库发生故障也不应该对其有任何影响。

事物的原理:事务开启之后,所有的操作都会临时保存在事务日志中,事务日志只有在得到 commit 命令才会同步到数据库中,其他的任何情况都会清空事务日志( rollback ,断开连接)。

隐式事物:默认情况下,MySQL 中的事务是默认自动提交的,比如INSERT、DELETE语句,都可以看做开启了一个事物,自动提交。

显式事物:在需要原子性操作的时候,需要手动开启事务。

使用场景:转账、订单的生成、付款等。

2 事务的创建

主要介绍显示事物的创建。

前提:需要关闭隐式事物的自动提交

SET autocommit = 0;

创建事务的完整语法:

START TRANSACTION; # 开启事物
SQL 语句..;
SQL 语句..;
SQL 语句..;
...
COMMIT[ROLLBACK]; # 提交事务(COMMIT)或回滚事务(ROLLBACK)

示例:

# 张三向李四转账 500
SET autocommit = 0;
START TRANSACTION;
UPDATE account SET balance = balance - 500 WHERE username = '张三';
UPDATE account SET balance = balance + 500 WHERE username = '李四';
COMMIT;

3 隔离级别

对于同时运行的多个事务,当这些事务访问数据库中相同的数据时,如果没有采取必要的隔离机制,就会导致各种并发问题。比如脏读、幻读、不可重复读。

  • 脏读(Drity Read):对于两个事务T1、T2,T1读取了已经被T2更新但是还没提交的字段。之后,如果T2回滚,T1读取的内容就是临时且无效的。
  • 不可重复读(Non-repeatable read):在一个事务的两次查询之中数据不一致,这可能是两次查询过程中间插入了一个事务更新的原有的数据。
  • 幻读(Phantom Read):在一个事务的两次查询中数据笔数不一致,例如有一个事务查询了几列(Row)数据,而另一个事务却在此时插入了新的几列数据,先前的事务在接下来的查询中,就会发现有几列数据是它先前所没有的。

为此,引入了数据库事务的隔离级别来避免事务的并发问题。

一个事务和其他事务隔离的程序称为隔离级别。数据库规定了多种事务隔离级别,不同隔离级别对应不同的干扰程序,隔离级别越高,数据一致性就越好,但是并发性就越低。

为了满足事务的四大特性,数据库定义了4种不同的事务隔离级别,从低到高依次是:

  • READ-UNCOMMITTED(读取未提交): 最低的隔离级别,允许读取尚未提交的数据变更,可能会导致脏读、幻读或不可重复读。
  • READ-COMMITTED(读取已提交): 允许读取并发事务已经提交的数据,可以阻止脏读,但是幻读或不可重复读仍有可能发生。
  • REPEATABLE-READ(可重复读): 对同一字段的多次读取结果都是一致的,除非数据是被本身事务自己所修改,可以阻止脏读和不可重复读,但幻读仍有可能发生。
  • SERIALIZABLE(可串行化): 最高的隔离级别,完全服从ACID的隔离级别。所有的事务依次逐个执行,这样事务之间就完全不可能产生干扰,也就是说,该级别可以防止脏读、不可重复读以及幻读。

下表展示了四种隔离级别的强度,会造成并发问题用表示,不会造成并发问题用×表示:

隔离级别 脏读 不可重复读 幻影读
READ-UNCOMMITTED
READ-COMMITTED ×
REPEATABLE-READ × ×
SERIALIZABLE × × ×

每启动一个 MySQL 客户端程序,就会获取一个单独的数据库连接。每个数据库连接都会有一个全局变量 @@tx_isolation ,表示当前的事务隔离级别。 设置隔离级别:

SET SESSION|GLOBAL TRANSACTION ISOLATION LEVEL 隔离级别名;
# SESSION表示设置当前连接的隔离级别
# GLOBAL表示设置系统隔离级别

查看当前的隔离级别:

SELECT @@tx_isolation;

Oracle 默认支持 2 种事务隔离级别:READ COMMITTED(读已提交)和SERIALIZABLE(串行化)。Oracle 默认的事务隔离级别是 READ COMMITTED(读已提交)。

MySQL 支持 4 种事务隔离级别。MySQL 默认的事务隔离级别是 REPEATABLE READ(可重复读)。

在分布式事物中,一般会使用最高的隔离级别SERIALIZABLE

posted @ 2022-01-27 06:32  yyyz  阅读(20)  评论(0编辑  收藏  举报