一、事务概念
事务由一条或多条SQL语句组成,这些语句在逻辑上存在相关性,共同完成一个任务,事务主要用于处理操作量大,复杂度高的数据。如转账就涉及多条SQL语句,包括查询余额(select)、在当前账户上减去指定金额(update)、在指定账户上加上对应金额(update)等,将多条SQL语句打包便构成了一个事务
MySQL同一时刻可能存在大量事务,若不对这些事务加以控制,在执行时就可能会出现问题。如单个事务内部的某些SQL语句执行失败,或是多个事务同时访问同一份数据导致数据不一致的问题
一个完整的事务并不是简单的SQL集合,事务还需要满足如下四个属性(简称ACID):
原子性(Atomicity,又称不可分割性): 一个事务中的所有操作,要么全部完成,要么全部不完成,不会结束在中间某个环节。事务在执行过程中若发生错误,则会自动回滚到事务开始前的状态,就像这个事务从来没有执行过一样
持久性(Consistency): 事务处理结束后,对数据的修改是永久的,即便系统故障也不会丢失
隔离性(Isolation,又称独立性): 数据库允许多个事务同时访问同一份数据,隔离性可以保证多个事务在并发执行时,不会因为由于交叉执行而导致数据的不一致
一致性(Durability): 在事务开始前和事务结束后,数据库的完整性没有被破坏,这表示写入的资料必须完全符合所有的预设规则,这包含资料的精确度、串联型以及后续数据库可以自发性地完成预定的工作
为什么会出现事务?
事务被MySQL编写者设计出来,本质是为了当应用程序访问数据库的时候,事务能够简化编程模型,不需要用户考虑各种各样的潜在错误和并发问题
若MySQL只单纯的提供数据存储服务,那么用户在访问数据库时就需自行考虑各种潜在问题,包括网络异常、服务器宕机等。因此事务本质是为了应用服务的,而不是伴随着数据库系统天生就有的
二、事务的版本支持
通过show engines可查看数据库引擎
Engine: 存储引擎名称
Support: 表示服务器对存储引擎的支持级别,YES支持,NO不支持,DEFAULT表示数据库默认使用的存储引擎,DISABLED表示支持引擎但已将其禁用
Comment: 表示存储引擎的简要说明
Transactions: 表示存储引擎是否支持事务,可以看到仅有InnoDB存储引擎支持事务
XA: 表示存储引擎是否支持XA事务
Savepoints: 表示存储引擎是否支持保存点
三、事务的提交方式
查看事务的提交方式
事务常见的提交方式有两种:自动提交、手动提交
通过show命令查看autocommit全局变量,可以查看事务的自动提交是否被打开(默认打开)
注意:autocommit的值为ON表示自动提交打开;值为OFF表示自动提交关闭,即需使用手动提交的方式进行事务的提交
设置自动提交
通过set命令设置autocommit全局变量的值,可以打开或关闭事务的自动提交
四、事务的相关演示
准备工作
为了演示,将MySQL的隔离级别设置成读未提交,易于观察实验现象
设置全局隔离级别后当前会话的隔离级别不会改变,只会影响后续与MySQL新建立的连接,需重启终端才能看到会话的隔离级别改变
创建一个银行用户表,表中包含用户的id、姓名和账户余额
4.1 常规操作
启动两个终端,左终端使用begin或start transaction命令启动一个事务,右终端查看银行用户表中的信息
左终端中的事务向表中插入一条记录,由于将隔离级别设置成了读未提交,因此在左终端中的事务使用commit提交之前,在右终端中就能查看到事务向表中插入的记录
左终端的事务使用savepoint命令创建一个保存点,然后继续向表中插入一条记录,此时在右终端中也能看到新插入的记录
左终端的事务使用rollback命令回滚到保存点s1,右终端在查看表中数据时就看不到第二条记录了
左终端的事务使用rollback命令回滚到事务最开始,右终端在查看表中数据时就看不到任何记录了
注意:
使用 begin或start transaction,可以启动一个事务
使用 savepoint 保存点,可以在事务中创建指定名称的保存点
使用 rollback to 保存点,可以让事务回滚到指定保存点
使用 rollback,可以直接让事务回滚到最开始
使用 commit,可以提交事务,提交事务后就不能回滚了
4.2 原子性
在左终端中启动一个事务,在右终端查看银行用户表中的信息。左终端中的事务向表中插入一条记录,由于隔离级别是读未提交,因此在右终端中能够查询到插入的这条记录
若左终端的事务在提交前因为某些原因与MySQL断开连接,那么MySQL会自动让事务回滚到最开始,右终端中就看不到之前插入的记录了
4.3 持久性
在左终端中启动一个事务,在右终端查看银行用户表中的信息。左终端中的事务向表中插入一条记录,由于隔离级别是读未提交,因此在右终端中能够查询到插入的这条记录
左终端中的事务在提交后与MySQL断开连接,这时右终端中仍然可以看到之前插入的记录,因为事务提交后数据就持久化
4.4 单条SQL与事务的关系
通过4.2和4.3的实验不难看出,使用begin或start transaction启动的事务,都必须要使用commit命令手动提交,数据才会被持久化,即使设置了autocommit
实际全局变量autocommit是否被设置影响的是单条SQL语句,InnoDB中的每一条SQL都会默认被封装成事务
autocommit为ON,则单条SQL语句执行后会自动被提交,若为OFF,则SQL语句执行后需要使用commit进行手动提交
如通过show命令查看autocommit的值为ON,表示事务的提交方式是自动提交,此时银行用户表中有一条记录
在左终端中直接向表中新插入一条记录,由于隔离级别是读未提交,因此在右终端中肯定能够查询到新插入的这条记录
但就算左终端在执行单条SQL后不使用commit进行提交,而直接与MySQL断开连接,这时右终端仍然可以看到之前新插入的记录了,因为单条SQL在执行后被自动提交持久化了
若将autocommit设置为OFF,表示事务执行后需手动提交,此时银行用户表中有两条记录
在左终端中直接向表中新插入一条记录,由于隔离级别是读未提交,因此在右终端中肯定能够查询到新插入的这条记录
但若此时左终端不使用commit进行提交,而直接与MySQL断开连接,那么这时右终端中就看不到之前新插入的记录了,因为这时单条SQL执行后需使用commit手动提交后才会持久化,在commit之前与MySQL断开连接则会自动进行回滚操作
所以之前的博客中一直都在使用单SQL事务,autocommit默认是打开的,因此单SQL事务执行后自动提交了