废话不多说,今天我们来讲解 MySQL 的事务吧 😃😃😃
一、事务的概念
那到底何为事务呢?
我们把需要保证原子性 、隔离性、一致性和持久性的一个或多个数据库操作称之为一个事务 。
它大致分为如下几个状态:
活动的(active)
事务对应的数据库操作正在执行过程中时,我们就说该事务处在活动的状态。
部分提交的(partially committed)
当事务中的最后一个操作执行完成,但由于操作都在内存中执行,所造成的影响并没有刷新到磁盘时,我们就说该事务处在部分提交的状态。
失败的(failed)
当事务处在活动的或部分提交的状态时,可能遇到了某些错误(数据库自身的错误、操作系统错误或者直接断电等)而无法继续执行,或者人为的停止当前事务的执行,我们就说该事务处在失败的状态。
中止的(aborted)
如果事务执行了半截而变为失败的状态,换句话说,就是要撤销失败事务对当前数据库造成的影响。专业术语就是,把这个撤销的过程称之为回滚 。当回滚操作执行完毕时,也就是数据库恢复到了执行事务之前的状态,我们就说该事务处在了中止的状态。
提交的(committed)
当一个处在部分提交的状态的事务将修改过的数据都同步到磁盘上之后,我们就可以说该事务处在了提交的状态。
小贴士:MySQL 中并不是每一个存储引擎都支持事务,目前只有 InnoDB 和 NDB 存储引擎支持
二、事务的特性
Atomicity(原子性):一个事务必须被视为一个不可分割的最小工作单元,整个事务中的所有操作要么全部提交成功,要么全部失败回滚,对于一个事务来说,不可能只执行其中的一部分操作。
Consistency(一致性):数据库总是从一个一致性状态转换到另一个一致状态。
Isolation(隔离性):通常来说,一个事务所做的修改在最终提交以前,对其他事务是不可见的。
Durability(持久性):一旦事务提交,则其所做的修改就会永久保存到数据库中,此时即使系统崩溃,修改的数据也不会丢失。
关于事务这些特性的举例,大家都是以非常经典的转账为例,我这里就不讲了(偷懒,逃)💨💨💨
三、事务的基本使用
我们说事务的本质其实只是一系列数据库操作,只不过这些数据库操作符合 ACID 特性而已,那么 MySQL 中如何将某些操作放到一个事务里去执行的呢?
1、开启事务
方式一:
BEGIN [WORK];
BEGIN 语句代表开启一个事务,后边的单词 WORK 可有可无。开启事务后,就可以继续写若干条语句,这些语句都属于刚刚开启的这个事务。
mysql> BEGIN;
Query OK, 0 rows affected (0.00 sec)
mysql> 加入事务的语句...
方式二:
START TRANSACTION;
START TRANSACTION 语句和 BEGIN 语句有着相同的功效,都标志着开启一个事务。
mysql> START TRANSACTION;
Query OK, 0 rows affected (0.00 sec)
mysql> 加入事务的语句...
不过可以在 START TRANSACTION 语句后边跟随几个修饰符:
- READ ONLY :标识当前事务是一个只读事务,也就是属于该事务的数据库操作只能读取数据,而不能修改数据。
- READ WRITE :标识当前事务是一个读写事务,也就是属于该事务的数据库操作既可以读取数据,也可以修改数据。
- WITH CONSISTENT SNAPSHOT :启动一致性读。
举例:
START TRANSACTION READ ONLY; # 开启一个只读事务
小贴士:READ ONLY 和 READ WRITE 不可以同时使用,因为一个事务不可能又是只读又是读写吧,但是它们都可以配合 WITH CONSISTENT SNAPSHOT 一起使用。
2、提交事务
开启事务之后就可以继续写需要放到该事务中的语句了,当最后一条语句写完了之后,我们就可以提交该事务了
COMMIT [WORK]
COMMIT 语句就代表提交一个事务,后边的 WORK 可有可无,我们举一个例子吧:
mysql> BEGIN; # 开启一个事务
Query OK, 0 rows affected (0.00 sec)
mysql> UPDATE account SET balance = balance - 10 WHERE id = 1; # 账户 1 的余额减10
Query OK, 1 row affected (0.02 sec)
mysql> UPDATE account SET balance = balance + 10 WHERE id = 2; # 账户 2 的余额加10
Query OK, 1 row affected (0.00 sec)
mysql> COMMIT; # 提交事务
Query OK, 0 rows affected (0.00 sec)
3、中止事务
我们的事务执行到一半发现某条语句写错了,我们需要进行回滚。
ROLLBACK [WORK]
ROLLBACK 语句就代表中止并回滚一个事务,后边的 WORK 可有可无类似的,我们还是举一个例子吧:
mysql> BEGIN; # 开启一个事务
Query OK, 0 rows affected (0.00 sec)
mysql> UPDATE account SET balance = balance - 10 WHERE id = 1; # 账户 1 的余额减10
Query OK, 1 row affected (0.00 sec)
mysql> UPDATE account SET balance = balance + 1 WHERE id = 2; # 账户 2 的余额加10
Query OK, 1 row affected (0.00 sec)
mysql> ROLLBACK; # 回滚事务
Query OK, 0 rows affected (0.00 sec)
小贴士:ROLLBACK 语句是人为手动的去回滚事务时才去使用的,如果事务在执行过程中遇到了某些错误而无法继续执行的话,事务自身会自动的回滚。
4、自动提交
说默认情况下,如果我们不显式的使用 START TRANSACTION 或者 BEGIN 语句开启一个事务,那么每一条语句都算是一个独立的事务,这种特性称之为事务的自动提交。
可以用过系统变量查看:
SHOW VARIABLES LIKE 'autocommit';
默认是ON,表示是开启自动提交的,我们要是关闭它的话只需要把该变量改为 OFF,或者自己手动提交或回滚事务。
5、隐式提交
因为某些特殊的语句而导致事务提交的情况称为隐式提交 ,有如下情况:
定义或修改数据库对象的数据定义语言(DDL),举个例子吧:
BEGIN; SELECT ... # 事务中的一条语句 UPDATE ... # 事务中的一条语句 ... # 事务中的其它语句 CREATE TABLE ... # 此语句会隐式的提交前边语句所属于的事务
隐式使用或修改 mysql 数据库中的表:
当我们使用 ALTER USER 、 CREATE USER 、 DROP USER 、 GRANT 、 RENAME USER 、 REVOKE 、 SET PASSWORD 等语句时也会隐式的提交前边语句所属于的事务。
事务控制或关于锁定的语句:
当我们在一个事务还没提交或者回滚时就又使用 START TRANSACTION 或者 BEGIN 语句开启了另一个事务时,会隐式的提交上一个事务,比如这样:
EGIN; SELECT ... # 事务中的一条语句 UPDATE ... # 事务中的一条语句 ... # 事务中的其它语句 BEGIN; # 此语句会隐式的提交前边语句所属于的事务
6、保存点
保存点可以让我们回滚到特定的位置,而不是一股脑的回滚的最初的地方(又回到最初的起点,默默的站在镜子前 😜😜😜)
基础语法:
AVEPOINT 保存点名称; # 设置保存点
ROLLBACK [WORK] TO [SAVEPOINT] 保存点名称 # 不跟随保存点名称的话,会直接回滚到事务执行之前的状态。
RELEASE SAVEPOINT 保存点名称; # 删除保存点
好了,到这里我们事务的非常基础的东西就讲完了。
巨人的肩膀: