文章目录:
1.事务概述
2.事务的ACID特性
3.如何使用事务?
3.1 显式事务
3.2 隐式事务
4.实操案例
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;
|