事务概念
MySQL事务是一个或者多个的数据库操作,要么全部执行成功,要么全部失败回滚。
事务是通过事务日志来实现的,事务日志包括:redo log和undo log。
事务状态
事务有以下五种状态:
- 活动的
- 部分提交的
- 失败的
- 中止的
- 提交的
活动
事务对应的数据库操作正在执行过程中时,我们就说该事务处在活动的状态。
部分提交
事务对应的数据库操作的最后一个操作执行完成,但是操作都在内存中,此刻还没有将数据刷新到磁盘中,这个状态称为部分提交
失败
当事务处在活动,或部分提交的状态时,遭到了某种错误(数据库自身的错误、操作系统错误或者直接断电等),导致操作不能进行下去,或者人为停止,这个状态称为失败。
中止
如果事务执行了半截而变为失败的状态,撤销失败事务对当前数据库造成的影响,我们把这个撤销的过程称之为回滚。
当回滚操作执行完毕时,也就是数据库恢复到了执行事务之前的状态,我们就说该事务处在了中止的状态。
提交
当一个处在部分提交的状态的事务将修改过的数据都同步到磁盘上之后,我们就可以说该事务处在了提交的状态。
有一张图我认为解释的非常好,给大家看看
只有当事务处于提交的或者中止的状态时,一个事务的生命周期才算是结束
讲了这么多,事务有什么作用?
可以保证复杂数据库操作数据的一致性,尤其是并发访问数据的时候。MySQL 事务主要用于处理操作量大,复杂度高的数据。
事务的特点
原子性(Atomicity,又称不可分割性)
事务的数据操作,要么全部执行成功,要么全部失败回滚到执行之前的状态,就像这个事务从来没有执行过一样。
#隔离性(Isolation,又称独立性)
多个事务之间是相互隔离,互不影响的。数据库允许多个并发事务同时对其数据进行读写和修改的能力,隔离性可以防止多个事务并发执行时由于交叉执行而导致数据的不一致。
四种隔离状态:
1. 读未提交(Read uncommitted)
2. 读提交(Read committed)
3. 可重复读(Repeatable read)
4. 串行化(Serializable)
一致性(Consistency)
在事务操作之前和之后,数据都是保持一个相同的状态,数据库的完整性没有被破坏。
原子性和隔离性,对一致性有着至关重要的影响。
持久性(Durability)
当事务操作完成后,数据会被刷新到磁盘永久保存,即便是系统故障也不会丢失。
知道这些理念了,那么具体应该怎么操作呢?
接下来是事务的实操
事务实操(语法)
基本语法
启动
方式1
mysql> begin;
Query OK, 0 rows affected (0.00 sec)
mysql> 事务操作SQL......
方式2
mysql> start transaction read only;
Query OK, 0 rows affected (0.00 sec)
mysql> 事务操作SQL......
注意,第二种方式如果设事务只读的话,对数据库进行写操作会报错。
提交(commit)
mysql> commit;
Query OK, 0 rows affected (0.00 sec)
回滚(rollback)
mysql> rollback;
Query OK, 0 rows affected (0.00 sec)
实操
首先,我们先创建个表
创建数据表:
create table account(
-> id int(10) auto_increment,
-> name varchar(30),
-> balance int(10),
-> primary key (id));
插入数据:
insert into account(name,balance) values('老王媳妇',100),('老王',10);
我们现在的需求是,老王媳妇转账给老王20元,这个时候涉及到多个操作,就可以用MySQL的事务。
执行步骤
执行步骤:
1. 从老王媳妇账户读取数据
2. 从老王媳妇账户上减掉20元
3. 从老王账户读取数据
4. 给老王账户增加20元
5. 执行提交成功
6. 此时老王媳妇账户只有80元啦,而老王账户有30元啦,老王高兴不得了咯
具体操作
事务启动
mysql> begin;
Query OK, 0 rows affected (0.01 sec)
语句1
mysql> update account set balance=balance-20 where id = 1;
Query OK, 1 row affected (0.00 sec)
Rows matched: 1 Changed: 1 Warnings: 0
语句2
mysql> update account set balance=balance+20 where id = 2;
Query OK, 1 row affected (0.00 sec)
Rows matched: 1 Changed: 1 Warnings: 0
提交
mysql> commit;
Query OK, 0 rows affected (0.01 sec)
事务设置与查看
查看事务开启情况:
mysql> SHOW VARIABLES LIKE 'autocommit';
+---------------+-------+
| Variable_name | Value |
+---------------+-------+
| autocommit | ON |
+---------------+-------+
要注意,默认事务是自动提交的,也就是每执行一条SQL就会提交。如果想执行完SQL还去操作事务,那么就需要显示开启begin,commit,rollback。显示开启就是像之前语法一样,要写出来。
自动提交很明显不方便我们对数据库的操作,那怎么样才能避免自动提交?
如何关闭自动提交?
第一种
显式的的使用START TRANSACTION或者BEGIN语句开启一个事务。
第二种
把系统变量autocommit的值设置为OFF。
SET autocommit = OFF;
关闭自动提交之后,称为隐式提交
隐式提交
当我们使用START TRANSACTION或者BEGIN语句开启了一个事务,或者把系统变量autocommit的值设置为OFF时,事务就不会进行自动提交,但是如果我们输入了某些语句之后就会悄悄的提交掉,就像我们输入了COMMIT语句了一样,这种因为某些特殊的语句而导致事务提交的情况称为隐式提交
一些隐式提交的语句
定义或修改数据库对象的数据定义语言(Data definition language,缩写为:DDL)
所谓的数据库对象,指的就是数据库、表、视图、存储过程等等这些东西。当我们使用CREATE、ALTER、DROP等语句去修改这些所谓的数据库对象时,就会隐式的提交前边语句所属于的事务。
BEGIN;
SELECT ... # 事务中的一条语句
UPDATE ... # 事务中的一条语句
... # 事务中的其它语句
CREATE TABLE ... # 此语句会隐式的提交前边语句所属于的事务
隐式使用或修改mysql数据库中的表
隐式使用或修改mysql数据库中的表。
当我们使用ALTER USER、CREATE USER、DROP USER、GRANT、RENAME USER、REVOKE、SET PASSWORD等语句时也会隐式的提交前边语句所属于的事务。
事务控制或关于锁定的语句
事务控制或关于锁定的语句。
当我们在一个事务还没提交或者回滚时就又使用START TRANSACTION或者BEGIN语句开启了另一个事务时,会隐式的提交上一个事务。
BEGIN;
SELECT ... # 事务中的一条语句
UPDATE ... # 事务中的一条语句
... # 事务中的其它语句
BEGIN; # 此语句会隐式的提交前边语句所属于的事务
或者当前的autocommit系统变量的值为OFF,我们手动把它调为ON时,也会隐式的提交前边语句所属的事务。
或者使用LOCK TABLES、UNLOCK TABLES等关于锁定的语句也会隐式的提交前边语句所属的事务。
#加载数据的语句
比如我们使用LOAD DATA语句来批量往数据库中导入数据时,也会隐式的提交前边语句所属的事务。
#关于MySQL复制的一些语句
使用START SLAVE、STOP SLAVE、RESET SLAVE、CHANGE MASTER TO等语句时也会隐式的提交前边语句所属的事务。
#其它的一些语句
使用ANALYZE TABLE、CACHE INDEX、CHECK TABLE、FLUSH、 LOAD INDEX INTO CACHE、OPTIMIZE TABLE、REPAIR TABLE、RESET等语句也会隐式的提交前边语句所属的事务