目录
一、事务概述
1.定义 :
2.事务和锁 :
二、事务操作
1.MySQL控制台事务的基本操作 :
2.代码演示 :
3.注意事项 :
三、事务的“ACID”特性 :
四、隔离机制
1.介绍 :
2.分类 :
3.常用指令 :
一、事务概述
1.定义 :
事务用于保证数据的一致性,它由一组相关的DML(Data Manipulation Language) 组成,并且该组的DML要么全部成功,要么全部失败。
eg : 转账操作就需要用事务来处理,用以保证数据的一致性。
2.事务和锁 :
当执行事务操作时(一组DML),MySQL会在表上加锁,防止其他用户修改表的数据,这对用户来讲是非常重要的。
二、事务操作
1.MySQL控制台事务的基本操作 :
1° START TRANSACTION : 开启一个事务;
2° SAVEPOINT point_name : 设置一个指定的保存点;
3° ROLLBACK TO point_name : 回退事务到指定保存点;
4° ROLLBACK : 回退全部事务,即直接恢复到事务刚开始的状态。
5° COMMIT : 提交事务,删除保存点,所有的操作生效,无法回退。
PS :
①保存点 : 用于记录当前事务执行状态的点,通过回退操作回到指定保存点时,会取消该保存点与当前状态之间的事务,即删除这两个点之间的操作。若使用ROLLBACK TO 指令直接跨过了多个保存点,那么被跨过的保存点不可以再返回。
②使用COMMIT语句后,会确认事务的变化,结束当前事务并删除所有的保存点,接着释放锁,数据生效。结束事务后,其他会话(MySQL的其他连接)便可以查看事务变化后的新数据(所有数据正式生效)。
2.代码演示 :
建立一张学生表,代码如下 :
CREATE TABLE IF NOT EXISTS `stus`(
`id` MEDIUMINT UNSIGNED UNIQUE NOT NULL,
`name` VARCHAR(64) NOT NULL DEFAULT '',
`score` DECIMAL(6,2) NOT NULL DEFAULT 0.0
) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin ENGINE INNODB;
SELECT * FROM stus;
使用START TRANSACTION 开始一个新的事务,向表中插入一些数据后,通过SAVEPOINT t1 设置保存点t1;再次向表中插入一些数据后,通过SAVEPOINT t2 设置保存点t2;接着,再次向表中插入一条数据。如下 :
# 开启一个新的事务
START TRANSACTION;
INSERT INTO `stus`
VALUES
(1, 'Cyan', 429),
(2, 'Ice', 433),
(3, 'Five', 412);
# 设置第一个保存点
SAVEPOINT t1;
INSERT INTO `stus`
VALUES
(4, 'Rain', 422),
(5, 'Reena', 400);
# 设置第二个保存点
SAVEPOINT t2;
INSERT INTO stus
VALUES
(6, 'Chris', 500);
SELECT * FROM stus;
这时,up突然发现t2保存点之后的DML操作,即第六条记录的添加,是有误的,不可能有人考这么高,于是想通过ROLLBACK TO 指令回到t2保存点时事务的状态,如下 :
ROLLBACK TO t2;
SELECT * FROM stus;
但是,up又发现t1保存点到t2保存点之间的DML操作,即第3,4,5条记录的添加,也是有问题的,不可能出现这么多400+,于是想通过ROLLBACK TO 指令回到t1保存点,如下 :
ROLLBACK TO t1;
SELECT * FROM stus;
这下up满意了,决定通过COMMIT操作正式提交事务,如下 :
SELECT * FROM stus;
那么,stus表最终便定格在了三条数据,如下 :
这时,如果还想继续通过ROLLBACK TO 指令来回退到t1保存点,会提示错误,如下 :
3.注意事项 :
1° 若未开始任何事务,默认情况下DML操作会自动提交,不能回滚并且回滚无实际意义。
2° 若开启一个事务后,在执行DML期间没有设置任何保存点,那么使用ROLLBACK指令会默认回退到事务刚开始的状态。
3° 若业已开启一个事务,在事务未提交之前可以创建多个保存点,并且可以选择回退到指定保存点。
4° MySQL事务机制的使用需要INNODB存储引擎的支持,MyISAM并不可行。
5° 除了START TRANSACTION操作外,SET AUTOCOMMIT = OFF 指令,也可以开始一个新的事务。
三、事务的“ACID”特性 :
1° 原子性(Atomicity):
原子性是指事务是一个不可分割的工作单位,事务中的操作要么都发生,要么都不发生。
2° 一致性(Consistency):
事务必须使数据库从一个一致性状态变换到另一个一致性状态。
3° 隔离性(Isolation):
事务的隔离性是指,多个用户并发的访问数据库时,数据库为每一个用户开启的事务不能被其他事务的操作数据所干扰,多个并发事务之间要相互隔离。(REPEATABLE Read)
4° 持久性(Durability):
持久性是指,一个事务一旦被提交,它对数据库中数据的改变就是永久性的,接下来即使数据库发生故障也不应该对其有任何影响。
四、隔离机制
1.介绍 :
当多个连接开启各自事务来操作数据库中的数据时,数据库系统DBS要负责隔离操作,以保证各个连接在获取数据时的准确性。
若不考虑隔离的问题,可能会引发脏读,幻读,不可重复读等问题。
PS :
①脏读 : Dirty Read. 当一个事务读取到了另一个事务尚未提交的修改时,就会发生脏读。
②幻读 : Phantom Read. 当同一查询在同一事务中多次进行时,由于其他提交事务所做的插入操作,使得当前事务每次返回不同的查询结果,此时发生幻读。
③不可重复读 : Nonrepeatable Read. 当同一查询在同一事务中多次进行时,由于其他提交事务所做的删除或修改操作,使得当前事务每次返回不同的查询结果,此时发生不可重复读。
PS :
①脏读指的是读到了其他事务未提交的修改;而幻读和不可重复读都是在其他事务已经提交的前提下。②为什么要避免脏读,幻读,和不可重复读?
因为用户连接到数据库,开始一个事务后,肯定是想读取到开启时刻数据库中的数据。
2.分类 :
MySQL中支持四种隔离级别,隔离级别不同,事务与事务之间的隔离程度便不同。具体分类如下 :
隔离级别越高,性能也越差。
PS :
①Read Uncommitted : 该隔离级别下的事务可以读到其他事务未提交和已提交的操作所改变的数据。
②Read Committed : 该隔离级别下的事务可以读到其他事务已提交的修改,删除,增加操作所改变的数据。
③Repeatable Read : 这是MySQL默认的隔离级别(一般不做修改)。该隔离级别下的事务可以读到启动事务时刻数据库中的数据,并且不会被其他事务所进行的DML操作所影响。
④Seralizable : 该隔离级别最牛逼。事务要对某数据库中的指定表进行访问时,会先判断当前表有没有其他事务正在操作,如果有,当前事务就会一直等待,直到没有其他事务操作该表时,才能访问成功,该隔离级别下读取到的数据是其他事务修改后的数据,但是由于最后已经没有其他事务操作要访问的数据,所以不会出现返回的查询结果不一致的情况。
演示(Seralizable) :
在CMD下登录两个用户,并将要访问的数据的用户的隔离级别修改为Seralizable,而操作stus表的用户仍是默认的Repeatable。如下图所示 :
此时,分别在两个会话下开启事务,并且令操作stus表的事务进行数据的修改和添加操作。如下 :
继续,在SERIALIZABLE隔离级别用户下访问stus,会因为加锁而等待,如下图所示 :
这时,令正在操作stus表的用户提交事务,则要访问stus表的用户才可以成功方法,如下图所示 :
3.常用指令 :
1° 查看当前会话(用户)的隔离级别 :
SELECT @@TRANSACTION_ISOLATION;
2° 查看你当前系统的隔离级别 :
SELECT @@GLOBAL.TRANSACTION_ISOLATION;
3° 设置当前会话的隔离级别 :
SET SESSION TRANSACTION ISOLATION LEVEL isolation_name;
4° 设置当前系统的隔离级别 :
SET GLOBAL TRANSACTION ISOLATION LEVEL isolation_name;
eg :
# 查看当前连接的隔离级别
SELECT @@transaction_isolation;
# 查看当前系统的隔离级别
SELECT @@GLOBAL.TRANSACTION_ISOLATION;
PS :
如何修改MySQL默认的隔离级别?
全局修改,在my.ini配置文件最后加上transaction-isolation = 参数。
其中,参数可以是——(注意“-”格式)
①READ-UNCOMMITTED;
②READ-COMMITTED;
③REPEATABLE-READ;
④SERIALIZABLE;
System.out.println("END--------------------------------------------------------------------------------");