MySQL高级篇——事务的概述与简单应用
Posted 张起灵-小哥
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了MySQL高级篇——事务的概述与简单应用相关的知识,希望对你有一定的参考价值。
文章目录:
1.事务概述
首先,我们可以查看一下各种存储引擎对事务的支持情况。 仅有INNODB是支持事务的。
事务: 一组逻辑操作单元,使数据从一种状态变换到另一种状态。 事务处理的原则: 保证所有事务都作为 一个工作单元 来执行,即使出现了故障,都不能改变这种执行方式。当在一个事务中执行多个操作时,要么所有的事务都被提交( commit ) ,那么这些修改就 永久 地保存下来;要么数据库管理系统将 放弃 所作的所有 修改 ,整个事务回滚 ( rollback ) 到最初状态。
2.事务的ACID特性
原子性( atomicity ): 原子性是指事务是一个不可分割的工作单位,要么全部提交,要么全部失败回滚。 一致性( consistency ): (国内很多网站上对一致性的阐述有误,具体你可以参考 Wikipedia 对 Consistency 的阐述) 根据定义,一致性是指事务执行前后,数据从一个 合法性状态 变换到另外一个 合法性状态 。这种状态是 语义上 的而不是语法上的,跟具体的业务有关。 那什么是合法的数据状态呢?满足 预定的约束 的状态就叫做合法的状态。通俗一点,这状态是由你自己来定义的(比如满足现实世界中的约束)。满足这个状态,数据就是一致的,不满足这个状态,数据就 是不一致的!如果事务中的某个操作失败了,系统就会自动撤销当前正在执行的事务,返回到事务操作之前的状态。 隔离型( isolation): 事务的隔离性是指一个事务的执行 不能被其他事务干扰 ,即一个事务内部的操作及使用的数据对 并发 的 其他事务是隔离的,并发执行的各个事务之间不能互相干扰。 持久性( durability ): 持久性是指一个事务一旦被提交,它对数据库中数据的改变就是 永久性的 ,接下来的其他操作和数据库故障不应该对其有任何影响。 持久性是通过 事务日志 来保证的。日志包括了 重做日志 和 回滚日志 。当我们通过事务对数据进行修改的时候,首先会将数据库的变化信息记录到重做日志中,然后再对数据库中对应的行进行修改。这样做的好处是,即使数据库系统崩溃,数据库重启后也能找到没有更新到数据库系统中的重做日志,重新执行,从而使事务具有持久性。
3.如何使用事务?
使用事务有两种方式,分别为 显式事务 和 隐式事务 。
3.1 显式事务
步骤 1 : START TRANSACTION 或者 BEGIN ,作用是显式开启一个事务。 START TRANSACTION 语句相较于 BEGIN 特别之处在于,后边能跟随几个 修饰符 : ① READ ONLY :标识当前事务是一个 只读事务 ,也就是属于该事务的数据库操作只能读取数据,而不能修改数据。 ② READ WRITE :标识当前事务是一个 读写事务 ,也就是属于该事务的数据库操作既可以读取数据,也可以修改数据。 ③ WITH CONSISTENT SNAPSHOT :启动一致性读。 步骤 2 : 一系列事务中的操作(主要是 DML ,不含 DDL ) 步骤 3 : 提交事务 或 中止事务(即回滚事务)
mysql> BEGIN;
#或者
mysql> START TRANSACTION;
# 提交事务。当提交事务后,对数据库的修改是永久性的。
mysql> COMMIT;
# 回滚事务。即撤销正在进行的所有没有提交的修改
mysql> ROLLBACK;
# 将事务回滚到某个保存点。
mysql> ROLLBACK TO [SAVEPOINT]
3.2 隐式事务
MySQL 中有一个系统变量 autocommit :(表示事务在默认情况下是自动提交的)
当然,如果我们想关闭这种 自动提交 的功能,可以使用下边两种方法之一: 显式的的使用 START TRANSACTION 或者 BEGIN 语句开启一个事务。这样在本次事务提交或者回滚前会暂时关闭掉自动提交的功能。 把系统变量 autocommit 的值设置为 OFF ,就像这样:
SET autocommit = OFF;
#或
SET autocommit = 0;
#set autocommit = false;
SHOW VARIABLES LIKE 'autocommit';#默认是ON
UPDATE account SET balance = balance - 10 WHERE id = 1; #此时这条DML操作是一个独立的事务
UPDATE account SET balance = balance + 10 WHERE id = 2; #此时这条DML操作是一个独立的事务
SET autocommit = FALSE; #针对于DML操作是有效的,对DDL操作是无效的。
UPDATE account SET balance = balance - 10 WHERE id = 1;
UPDATE account SET balance = balance + 10 WHERE id = 2;
COMMIT; #或rollback; 此时以上两个UPDATE为一个事务整体
#我们在autocommit为true的情况下,使用start transaction 或begin开启事务,那么DML操作就不会自动提交数据
START TRANSACTION;
UPDATE account SET balance = balance - 10 WHERE id = 1;
UPDATE account SET balance = balance + 10 WHERE id = 2;
COMMIT; #或rollback;
当然在mysql中,也有一些隐式提交数据的情况:
数据定义语言( Data definition language ,缩写为: DDL ) 隐式使用或修改 mysql 数据库中的表 事务控制或关于锁定的语句 ① 当我们在一个事务还没提交或者回滚时就又使用 START TRANSACTION 或者 BEGIN 语句开启了另一个事务时,会 隐式的提交 上一个事务。即: ② 当前的 autocommit 系统变量的值为 OFF ,我们手动把它调为 ON 时,也会 隐式的提交 前边语句所属的事务。 ③ 使用 LOCK TABLES 、 UNLOCK TABLES 等关于锁定的语句也会 隐式的提交 前边语句所属的事务。
4.实操案例
USE atguigudb2;
CREATE TABLE user(
NAME VARCHAR(15) PRIMARY KEY
);
SELECT * FROM user;
下面我们开启一个事务,向表中插入一条数据,然后提交。
BEGIN;
INSERT INTO user VALUES('张三');
COMMIT;
SELECT * FROM user;
再开启一个事务,向表中添加两条数据,第二个INSERT会报错的,此时提交事务,只有第一个INSERT会成功的。
BEGIN;
INSERT INTO user VALUES('李四');
INSERT INTO user VALUES('李四');
COMMIT;
SELECT * FROM user;
下面我们将表清空,采用ROLLBACK回滚进行练习。
TRUNCATE TABLE user;
SELECT * FROM user;
BEGIN;
INSERT INTO user VALUES('张三');
COMMIT;
SELECT * FROM user;
下面还像上面的操作一样,我们向表中插入两条一样的数据,同样第二个INSERT会报错。
执行一下ROLLBACK,看看数据库表中数据如何?
INSERT INTO user VALUES('李四'); #ROLLBACK回滚到此处
INSERT INTO user VALUES('李四');
ROLLBACK;
SELECT * FROM user;
下面再将表中数据清空,做新的操作。 将completion_type变量的值修改为1。
TRUNCATE TABLE user;
SELECT * FROM user;
SELECT @@completion_type;
SET @@completion_type = 1;
SELECT @@completion_type;
BEGIN;
INSERT INTO user VALUES('张三');
COMMIT; #ROLLBACK回滚到此处
SELECT * FROM user;
INSERT INTO user VALUES('李四');
INSERT INTO user VALUES('李四');
ROLLBACK;
SELECT * FROM user;
下面演示一下INNODB和MYISAM在事务背景下的案例。
CREATE TABLE test1(i INT) ENGINE = INNODB;
CREATE TABLE test2(i INT) ENGINE = MYISAM;
#针对于innodb表
BEGIN;
INSERT INTO test1 VALUES (1);
SELECT * FROM test1;
可以看到,存储引擎为INNODB的表,在ROLLBACK之后,会正常回滚到事务最开始的状态,也即回滚之后表中没有任何数据。
ROLLBACK;
SELECT * FROM test1;
#针对于myisam表:不支持事务
BEGIN;
INSERT INTO test2 VALUES (1);
SELECT * FROM test2;
可以看到,存储引擎为MYISAM的表,在ROLLBACK之后,表中插入的那条数据仍然存在,也即MYISAM存储引擎不支持事务。
ROLLBACK;
SELECT * FROM test2;
下面针对 SAVEPOINT 举例。
#举例3:体会savepoint
CREATE TABLE user3(
NAME VARCHAR(15),
balance DECIMAL(10,2)
);
BEGIN;
INSERT INTO user3(NAME,balance) VALUES('张三',1000);
COMMIT;
SELECT * FROM user3;
BEGIN;
UPDATE user3 SET balance = balance - 100 WHERE NAME = '张三'; # 900
UPDATE user3 SET balance = balance - 100 WHERE NAME = '张三'; # 800
SAVEPOINT s1;#设置保存点
UPDATE user3 SET balance = balance + 1 WHERE NAME = '张三'; # 801
ROLLBACK TO s1; #回滚到保存点
SELECT * FROM user3;
此时ROLLBACK TO s1就正常的回滚到了保存点s1的位置,balance为800。
下面是针对整个事务进行回滚,则回到了最初添加数据balance为1000的时候。
ROLLBACK; #回滚操作
SELECT * FROM user3;
以上是关于MySQL高级篇——事务的概述与简单应用的主要内容,如果未能解决你的问题,请参考以下文章