数据库中的事务用来管理增、删、改操作,查询不需要事务管理,因为它并不会修改数据库中的数据。
在 MySQL 中只有使用了InnoDB 数据库引擎 的数据库或表才支持事务。
事务的特性
事务具有ACID四性,即原子性(Atomicity)、一致性(Consistency)、隔离性(Isolation)、持久性(Durability)。
-
原子性
事务是作为一个整体来执行的,某个事务中的全部操作要么全部成功,要么全部失败。 若事务失败,则数据库状态回滚到事务执行之前。
-
一致性
事务必须使数据库从一个一致性状态变换到另外一个一致性状态。比如在银行中两个账户转账前后的储蓄总和不变,这就是从转账前的一致性状态转变为了转账后的一致性状态。保证事务的一致性,就是保证数据库的完整性约束没有被破坏。
-
隔离性
数据库中不同事务可以并发执行,但它们各自之间是互不影响的,事务a不会被事务b的操作数据干扰。
-
持久性
持久性是指一个事务一旦被提交(commit),它对数据库中数据的改变就是永久性的。
对于事务的原子性,只要将事务作为一个整体去执行就可以了,一荣俱荣,一损俱损;
对于事物的一致性,需要设置数据库的完整性约束,保证数据要服从此约束;
对于事务的持久性,若服务器宕机,此时事务的数据还未进行持久化,会有什么影响呢?已提交的事务,肯定已经持久化到磁盘中,还未提交的事务,相应的数据会回滚。这是为什么,继续往下看到事务日志就明白了。
以上这四种性质,原子性、一致性、持久性都比较容易实现,比较复杂的是事务的隔离性。
事务的隔离级别
为了实现事务的隔离性,InnoDB数据库引擎中提供了4中事务隔离级别:
-
ISOLATION_READ_UNCOMMITTED 读未提交
读未提交是最低级别的隔离。
事务A修改了数据D,并且还未提交,当事务B再次查询数据D时,查询到的是事务A修改后的数据D。
-
ISOLATION_READ_COMMITTED 读已提交
事务A修改了数据D,并且已经提交,当事务B再次查询数据D时,查询到的是事务A修改后的数据D。若事务A未提交,则事务B查询到的数据只能是修改前的数据D。
-
ISOLATION_REPEATABLE_READ 可重复读
事务A修改了数据D,并且已经提交,当事务B再次查询数据D时,查询到的是事务A修改前的数据D。意思就是事务A对于数据D的修改,在事务B未提交时是不可见的,只有当事务B提交后才能看到其它事务提交的修改。
-
ISOLATION_SERIALIZABLE 串行化
串行化是最高级别的隔离。事务依次执行,不会产生冲突。
若不适当考虑事务的隔离级别, 在数据库中可能会引发下列问题:
画个表:
|
脏读 |
不可重复读 |
幻读 |
ISOLATION_READ_UNCOMMITTED |
√ |
√ |
√ |
ISOLATION_READ_COMMITTED |
× |
√ |
√ |
ISOLATION_REPEATABLE_READ |
× |
× |
√ |
ISOLATION_SERIALIZABLE |
× |
× |
× |
不可重复读:可以理解为有一个数据D,事务执行期间重复读取它,并不能保证每次读取的值都一样。
事务日志
数据库管理系统采用事务日志来保证事务的原子性、一致性和持久性。
如果每次更新都将数据持久化到磁盘,由于数据是随机的,会造成大量的随机IO,性能会非常差;但是如果每次更新不马上写盘,那一旦数据库崩溃,数据就会丢失。为了提高事务中更新操作的效率,MySQL中的大多数存储引擎都实现了事务日志。
使用事务日志,存储引擎在修改表的数据时只需要修改其内存拷贝,再把该修改行为记录到持久在硬盘上的事务日志中,而不用每次都将修改数据本身持久到磁盘。
事务日志采用的是追加的方式,因此写日志的操作是磁盘上一小块区域内的顺序I/O,而不像随机I/O需要在磁盘的多个地方移动磁头,所有采用事务日志的方式相对来说要快得多。
事务日志持久化以后,内存中被修改的数据在后台可以慢慢地刷回到磁盘。目前大多数存储引擎都是这样实现的,我们通常称之为预写式日志 (Write-Ahead Logging),因此修改数据需要写两次磁盘。
如果数据的修改已经记录到事务日志并持久化,但数据本身没有写回磁盘,此时系统崩溃,存储引擎在重启时能够自动恢复这部分修改的数据。具体的恢复方式则视存储引擎而定。
事务控制语句
- BEGIN 或 START TRANSACTION 显式地开启一个事务;
- COMMIT 会提交事务,并使已对数据库进行的所有修改成为永久性的;
- ROLLBACK 回滚会结束用户的事务,并撤销正在进行的所有未提交的修改;
- SAVEPOINT identifier,SAVEPOINT 允许在事务中创建一个保存点,一个事务中可以有多个 SAVEPOINT;
- RELEASE SAVEPOINT identifier 删除一个事务的保存点,当没有指定的保存点时,执行该语句会抛出一个异常;
- ROLLBACK TO identifier 把事务回滚到标记点;
- SET TRANSACTION 用来设置事务的隔离级别。InnoDB 存储引擎提供事务的隔离级别有READ UNCOMMITTED、READ COMMITTED、REPEATABLE READ 和 SERIALIZABLE。
- SET AUTOCOMMIT=0 禁止自动提交
SET AUTOCOMMIT=1 开启自动提交
参考
https://www.runoob.com/mysql/mysql-transaction.html
https://blog.csdn.net/ncepu_Chen/article/details/94857481
https://zhuanlan.zhihu.com/p/43493165 深入理解数据库事务
https://blog.csdn.net/yinni11/article/details/81510035 事务日志