事务处理
事务处理(transaction processing)是一种机制, 用来管理必须成批执行的
SQL` 操作,保证数据库不包含不完整的操作结果。利用事务处理,可以保证一组操作不会中途停止,它们要么完全执行,要么完全不执行(除非明确指示)。如果没有错误发生,整组语句提交给(写到)数据库表;如果发生错误,则进行回退(撤销),将数据库恢复到某个已知且安全的状态,以此来维护数据库的完整性。
事务处理术语:
- 事务(transaction):指一组
SQL
语句; - 回退(rollback):指撤销指定
SQL
语句的过程; - 提交(commit):指将未存储的
SQL
语句结果写入数据库表; - 保留点(savepoint):指事务处理中设置的临时占位符(placeholder), 可以对它发布回退(与回退整个事务处理不同)。
事务处理用来管理 INSERT
、UPDATE
和 DELETE
语句。不能回退 SELECT
语句(回退 SELECT
语句也没有必要),也不能回退 CREATE
或 DROP
操 作。事务处理中可以使用这些语句,但进行回退时,这些操作也不撤销。
一般来说,事务是必须满足4个条件( ACID
)::原子性(Atomicity,或称不可分割性)、一致性(Consistency)、隔离性(Isolation,又称独立性)、持久性(Durability)。
- 原子性: 一个事务(
transaction
)中的所有操作,要么全部完成,要么全部不完成,不会结束在中间某个环节。事务在执行过程中发生错误,会被回滚(Rollback
)到事务开始前的状态,就像这个事务从来没有执行过一样。 - 一致性: 在事务开始之前和事务结束以后,数据库的完整性没有被破坏。这表示写入的资料必须完全符合所有的预设规则,这包含资料的精确度、串联性以及后续数据库可以自发性地完成预定的工作。
- 隔离性: 数据库允许多个并发事务同时对其数据进行读写和修改的能力,隔离性可以防止多个事务并发执行时由于交叉执行而导致数据的不一致。事务隔离分为不同级别,包括读未提交(
Read uncommitted
)、读提交(read committed
)、可重复读(repeatable read
)和串行化(Serializable
)。 - 持久性: 事务处理结束后,对数据的修改就是永久的,即便系统故障也不会丢失。
在 MySQL 命令行的默认设置下,事务都是自动提交的,即执行 SQL 语句后就会马上执行 COMMIT 操作。因此要显式地开启一个事务务须使用命令 BEGIN 或 START TRANSACTION,或者执行命令 SET AUTOCOMMIT=0,用来禁止使用当前会话的自动提交。
控制事务处理
BEGIN / START TRANSACTION
:显式地开启一个事务;COMMIT / COMMIT WORK
:提交事务,使已对数据库进行的所有修改成为永久性的;ROLLBACK / ROLLBACK WORK
:回滚会结束用户的事务,并撤销正在进行的所有未提交的修改;SAVEPOINT
:SAVEPOINT
允许在事务中创建一个保存点,一个事务中可以有多个SAVEPOINT
;RELEASE SAVEPOINT
:删除一个事务的保存点,当没有指定的保存点时,执行该语句会抛出一个异常;ROLLBACK TO
:把事务回滚到标记点;SET TRANSACTION
:用来设置事务的隔离级别。InnoDB
存储引擎提供事务的隔离级别有READ UNCOMMITTED
(读未提交)、READ COMMITTED
(读已提交,项目中常用)、REPEATABLE READ
(可重复读,Mysql
默认隔离级别) 和SERIALIZABLE
(串行化)。
简单示例:
mysql> use test; mysql> CREATE TABLE transaction_test(id int(5)) ENGINE = INNODB; # 创建数据表 mysql> SELECT * FROM transaction_test; Empty set (0.01 sec) mysql> BEGIN; # 开始事务 mysql> INSERT INTO runoob_transaction_test VALUE(1); mysql> INSERT INTO runoob_transaction_test VALUE(2); mysql> COMMIT; # 提交事务 mysql> SELECT * FROM transaction_test; +------+ | id | +------+ | 1 | | 2 | +------+ mysql> BEGIN; # 开始事务 mysql> INSERT INTO transaction_test VALUES(3); mysql> SAVEPOINT first_insert; # 声明一个保存点 mysql> INSERT INTO transaction_test VALUES(4); mysql> SAVEPOINT second_insert; # 声明一个保存点 mysql> INSERT INTO transaction_test VALUES(5); mysql> ROLLBACK TO second_insert; # 回滚到 second_insert 保存点 mysql> SELECT * FROM transaction_test; # 因为回滚所以数据没有插入 +------+ | id | +------+ | 1 | | 2 | | 3 | | 4 | +------+ mysql> ROLLBACK TO first_insert; mysql> SELECT * FROM transaction_test; +------+ | id | +------+ | 1 | | 2 | | 3 | +------+ mysql> COMMIT; # 执行 COMMIT 或 ROLLBACK 后保存点自动释放 复制代码