事务
概述
- 一个最小的不可再分的工作单元;通常一个事务对应一个完整的业务(例如银行账户转账业务,该业务就是一个最小的工作单元);完整的业务需要批量的DML(insert、update、delete)语句共同联合完成
- 事务只和DML语句有关,或者说DML语句才有事务。这个和业务逻辑有关,业务逻辑不同,DML语句的个数不同
- 事务是为数据安全操作提出的,用来维护数据库的完整性,保证成批的 SQL 语句要么全部执行,要么全部不执行
使用注意
- 在 MySQL 中只有使用了 Innodb 数据库引擎的数据库或表才支持事务
- 只在同一连接对象生效
事务的特征(ACID)
事务必须服从ACID原则
- 原子性(A):
- 事务是最小单位,不可再分
- 一致性(C):
- 必须保证同时成功或者同时失败;数据库的完整性没有被破坏;不能有数据丢失的情况。
- 隔离性(I):
- 消除事务间的相互影响;事务A和事务B之间具有隔离性
- 持久性(D):
- 保证事务执行的结果在磁盘上永久的存储
事务隔离性的后果
- 脏读:事务获取到其它事务执行过程中的结果
- 解决方案:事务执行过程中获取不到其它事务执行过程中的结果。
- 不可重复读(修改操作导致):事务执行过程中获取了其它事务不同的阶段的结果;
- 解决方案:事务在其它事务执行过程中开启,其它事务相对于该事务透明
- 幻读(插入或删除操作导致):事务执行过程中获取到其它事务不同阶段的结果。
- 解决方案:间隙锁。
事务的隔离级别
- 读未提交:
read uncommitted
- 事物A和事物B,事物A未提交的数据,事物B可以读取到;这里读取到的数据叫做
“脏数据”
- 这种隔离级别最低,这种级别一般是在理论上存在,数据库隔离级别一般都高于该级别
- 事物A和事物B,事物A未提交的数据,事物B可以读取到;这里读取到的数据叫做
- 读已提交:
read committed
- 事物A和事物B,事物A提交的数据,事物B才能读取到;这种隔离级别高于读未提交
- 换句话说,对方事物提交之后的数据,我当前事物才能读取到;这种级别可以避免“脏数据”;这种隔离级别会导致
“不可重复读取”
- Oracle默认隔离级别
- 可重复读:
repeatable read
- 事务A和事务B,事务A提交之后的数据,事务B读取不到
- 事务B是可重复读取数据
- 这种隔离级别高于读已提交
- 换句话说,对方提交之后的数据,我还是读取不到
- 这种隔离级别可以避免“不可重复读取”,达到可重复读取
- 比如1点和2点读到数据是同一个
- MySQL默认级别
- 虽然可以达到可重复读取,但是会导致“幻像读”
- 串行化:
serializable
可序列化:事务变成串行处理- 事务A和事务B,事务A在操作数据库时,事务B只能排队等待
- 这种隔离级别很少使用,吞吐量太低,用户体验差
- 这种级别可以避免“幻像读”,每一次读取的都是数据库中真实存在数据,事务A与事务B串行,而不并发
当前隔离级别:每次一个客户端连接服务器,服务器分配给它的隔离级别,修改时修改的是当前隔离级别。
全局隔离级别:数据库服务端默认的隔离级别(可重复读),在配置文件中写的,数据库加载时直接读取配置文件
事务操作
在 MySQL 的默认设置下,事务是自动提交的,即执行 SQL 语句后就会马上执行 COMMIT 操作
- 启用自动提交
SET AUTOCOMMIT=1
- 禁止自动提交
使用BEGIN
或START TRANSACTION
或SET AUTOCOMMIT=0
用来禁止使用当前会话(连接)的自动提交 - 提交事务(执行操作)
使用COMMIT
或COMMIT WORK
- 回滚事务(撤销操作)
使用ROLLBACK
或ROLLBACK WORK
,回滚会结束用户的事务,并撤销正在进行的所有未提交的修改; - 设置事务点
SAVEPOINT identifier
,SAVEPOINT
允许在事务中创建一个保存点,一个事务中可以有多个 SAVEPOINT; - 删除事务点
RELEASE SAVEPOINT identifier
删除一个事务的保存点,当没有指定的保存点时,执行该语句会抛出一个异常; - 回滚到事务点
ROLLBACK TO identifier
把事务回滚到标记点; - 设置隔离级别
SET TRANSACTION
用来设置事务的隔离级别。InnoDB 存储引擎提供事务的隔离级别有READ UNCOMMITTED、READ COMMITTED、REPEATABLE READ 和 SERIALIZABLE。
嵌套事务,子事务
使用保留点 SAVEPOINT
savepoint 是在数据库事务处理中实现“子事务”(subtransaction),也称为嵌套事务的方法
事务可以回滚到 savepoint 而不影响 savepoint 创建前的变化, 不需要放弃整个事务
ROLLBACK 回滚的用法可以设置保留点 SAVEPOINT,执行多条操作时,回滚到想要的那条语句之前
使用 SAVEPOINT
SAVEPOINT 保留点名称; // 声明一个 savepoint
ROLLBACK TO 保留点名称; // 回滚到savepoint
删除 SAVEPOINT保留点再事务处理完成(执行一条 ROLLBACK 或 COMMIT)后自动释放
MySQL5 以来,可以用:RELEASE SAVEPOINT 保留点名称;
– 删除指定保留点