事务介绍
事务是一种机制,用于管理成批执行的MySQL操作,并且要求满足ACID特性,以维护数据库的完整性即数据库不会包含不完整的操作结果。
MySQL的默认存储引擎InnoDB支持事务,但是存储引擎MyISAM不支持事务。
ACID特性
ACID特性是严谨的,但是想在事务中实现这些特性并不是一件容易的事,需要学习的还很多。
| 属性 | 简介 |
|---|---|
| 原子性(Atomicity) | 一组MySQL操作必须要求全部执行或者全部不执行。 |
| 一致性(Consistency) | 数据库状态的转换必须是从一个一致性状态转换到另外一个一致性状态。(一致性状态可以理解为是逻辑上正确的状态),所以要求事务在未完成前它不会错误的修改数据库状态。比如一个相互转账事务,会涉及到两个账户金额,一个新增,一个减少。在两个账户互相转帐的情况下不应该出现一个账户金额减少了,但是另外一个账户金额新增失败导致金额没变的情况。所以当遇到新增成功但是减少失败的情况下,相应的新增应该进行回滚操作,使数据库保持正确的状态。 |
| 隔离性(Isolation) | 多个事务进行(并发)情况下,任何事务都不应该影响到其他事务。 |
| 持久性(Durability) | 无论是系统或者是数据库错误,事务完成的提交应该已经保存在磁盘中。 |
常见术语
| 术语 | 简介 |
|---|---|
| 事务(TRANSACTION) | 简单意义上指的是一组Sql语句。 |
| 提交(COMMIT) | 将会话的操作结果存储到数据库。 |
| 回滚(ROLLBACK) | 也称为回退,将会话中的操作结果丢弃。 |
| 保留点(SAVEPOINT) | 一个事务中可以有多个保留点,可以回滚到指定保留点,这样可以避免回滚整个事务。 |
| 连接 | 每一次连接MySQL数据库都会产生一个连接通道。 |
| 会话 | 每打开一个MySQL客户端都会产生一个新的会话。 |
基本事务处理
自动提交
在事务中使用COMMIT可以提交事务,但是MySQL默认就是打开了自动提交autocommit = 1(0=关闭、1=开启),所以在没有指定语句BEGIN ... COMMIT的情况下,任何独立的Sql语句执行的结果都会被自动提交。不过DDL语句无论是在开启或者关闭自动提交情况下都会自动执行不可回滚。
关闭自动提交
两种方式
- 使用
SET autocommit = 0
在当前会话内有效。
- 在MySQL配置文件中修改
autocommit = 0,然后重启MySQL
一直有效。
开始事务
使用SATRT TRANSACTION或者BEGIN标识事务开始。
提交(COMMIT)
使用COMMIT提交事务操作结果到数据库。
回退(ROLLBACK)
使用ROLLBACK丢失事务操作结果。或者使用 ROLLBACK TO回退到指定的保留点,并丢失到该保留点之间的操作结果,例如ROLLBACK TO pointname。
保留点(SAVEPOINT)
使用SAVEPOINT创建保留点,比如 SAVEPOINT pointname。在执行ROLLBACK或者COMMIT完成事务后会自动释放保留点,或者使用RELEASE SAVEPOINT手动释放保留点(要求MySQL 5以上)。
基本事务处理总结
事务管理的是成批的MySQL操作,事务在处理时将一批Sql语句看成一个整体,无论是回滚还是提交都是处理作为整体的一批Sql语句的操作结果。
默认情况下是以事务开始语句为起点,期间的Sql语句都会作为一个整体,但是保留点就可以切割这个整体为更多的小块,所以可以更加灵活在事务中进行回滚处理。
并发问题
在多个事务同时执行(并发)的情况可能会有以下这些问题产生。
脏读
读取的数据是其他事务修改的但是未提交到数据库的脏数据。
不可重复读
单个事务内多次读取到的同一条数据不一致。
幻读
脏读和不可重复读的问题主要是某条记录上的数据不对,在数据库表上是横向的变化。但是幻读的现象是读取到的记录出现新增或者删减,在数据库表上是纵向的变化。
隔离机制
可以通过隔离机制在一定程度上解决并发问题。从读未提交到序列化,有4种隔离界别,且隔离级别越来越高,但是并发性也会相对越来越差。
读未提交(READ-UNCOMMITTED)
事务可以读取其他事务未提交的数据。
可以禁止脏读。
读已提交(READ-COMMITTED)
事务可以不能读取其他事务未提交的数据,可以读取已经提交的数据。
可以禁止不可重复读。
可重复读(REPEATABLE-READ)
事务第一次读取可以不能读取其他事务未提交的数据,可以读取已经提交的数据。但是除了第一次后,再读取同一条记录时只能得到到第一次读取的数据。
可以一定程度上禁止幻读。
序列化(SERIALIZABLE)
事务在第一次读取某条记录时就会加上行级锁,直到事务结束。会阻塞其他事务对同一条记录的读取。
完全禁止脏读、不可重复读、幻读。
设置隔离机制
两种方式
SET @@transaction_isolation = '隔离级别'
只在当前会话生效。例如
SET @@transaction_isolation = 'READ-COMMITTED';
- 在MySQL配置文件中修改
transaction_isolation的值,重启MySQL
一直有效。
锁
TODO 待补充