6.事务概述
6.1 事务概述:一个最小的不可再分的工作单元;通常一个事务对应一个完整的业务
- 多个操作要么都成功,要么都失败
- 事务只和DML语句有关,或者说DML语句才有事务
- 事务原则:ACID-
-
- 原子性(Automicity)、
- 一致性(Consistency)、
- 持久性、(Isolation)
- 隔离性(Durability)(脏读、幻读…)
- 将一组sql放在一个批次中去执行
- innodb支持,myISAM最新版本也支持
原子性:针对一个事务的两个步骤一起成功或一起失败,不能只发生其中一个动作,不允许分割
一致性:针对一个事务操作前和操作后的状态一致,数据库从一个正确的状态变化到另一个正确的状态。结果最终一致性
持久性:事务还没有提交,恢复到原状、已经提交了,持久化到数据库,一旦提交不可逆。
隔离性:针对多个用户同时并发操作,排除其他事务对本次事务的影响,互不干扰;数据库为每个用户开启事务,不能被其他事务的操作数据干扰。
6.2 隔离级别
6.2.1 隔离导致
- 脏读:一个事务读取了另一个事务未提交的数据
- 不可重复读:一个事物读取表中某一行数据,多次读取结果不同。(不一定是错误,只是某些场合不对)
- 虚读(幻读):一个事务内读取了别的事务插入的数据,导致前后读取不一致(一般是行影响,多了一行)
- 总结:不可重复读侧重修改,幻读侧重新增和删除。不可重复读要锁符合条件的行数据,幻读要锁表
6.2.2 隔离级别(isolation-level)
- 读未提交(READ UNCOMMITTED):一个事务还没提交时,它做的变更就能被别的事务看到。
- 读提交(Orlace默认级别READ COMMITTED):一个事务提交之后,它做的变更才会被其他事务看到。解决脏读。
- 可重复读(mysql默认级别REPEATABLE READ):事务不会读到其它事务提交的修改(一开始读到什么,最后也读到什么)解决脏读、不可重复读
- 串行化(SERIALIZABLE):解决了脏读、不可重复读、幻读,相当于单进程,效率低下。
6.2.3 事务作用范围-2种
- 全局级别(global):对所有会话有效
- 会话级别(session):只对当前会话有效
6.2.4设置事务隔离级别
SET [GLOBAL | SESSION] TRANSACTION ISOLATION LEVEL <isolation-level>
GLOBAL:代表设置全局事务级别
SESSION:代表设置会话事务级别
设置会话隔离级别为READ COMMITTED↓
SET TRANSACTION ISOLATION LEVEL READ COMMITTED;
或
SET SESSION TRANSACTION ISOLATION LEVEL READ COMMITTED;
设置全局隔离级别为READ COMMITTED↓
SET GLOBAL TRANSACTION ISOLATION LEVEL READ COMMITTED;
6.2.5 查看事务隔离级别
查看会话隔离级别
select @@tx_isolation;
show variables like '%isolation%';
查看全局隔离级别
select @@global.tx_isolation;
6.3. 事务开启、标志
-
Mysql默认开启
-
无论是否开启事务,都会马上执行命令,只是开启事务后将状态存入redo日志,commit后才写入磁盘
-
BEGIN; COMMIT; ROLLBACK;
-- 事务开启
BEGIN;
INSERT INTO testmd5(`name`,`pwd`) VALUES('李云',MD5('123456'));
COMMIT; -- 提交
BEGIN;
INSERT INTO testmd5(`name`,`pwd`) VALUES('王华',MD5('123456'));
ROLLBACK; -- 回滚
- 提交:成功的结束,将所有的DML语句操作历史记录和底层硬盘数据来一次同步
- 回滚:失败的结束,将所有DML语句操作历史记录全部清空
- mysql实现事务是根据undo日志和redo日志实现的
- undo:记录修改前的状态,rollback基于undo实现
- redo:记录修改后的状态,commit基于redo实现
- 无论是否开启事务,都会立刻执行,只是开启事务后将执行结果保存在redo中,commit之后才写入磁盘
- mysql中begin和start transaction区别
-
- begin或start transaction 都是显式开启一个事务,是等价的;
- commit 或commit work都是等价的;
- rollback或rollback work 也是等价的;
6.4 提交和回滚
- mysql默认情况下,事务是自动提交的,也就是说只要执行了一条DML语句就开启了事务,并且提交了事务
- 自动提交机制是可以关闭的
-- 事务开启
BEGIN;
INSERT INTO testmd5(`name`,`pwd`) VALUES('李云',MD5('123456'));
COMMIT; -- 提交
BEGIN;
INSERT INTO testmd5(`name`,`pwd`) VALUES('王华',MD5('123456'));
ROLLBACK; -- 回滚
- spring开启事务和mysql开启事务不一致时,以spring事务为主。
6.5 redis事务(补充)
- 参考:[Mysql事务]:https://blog.csdn.net/qq_42294627/article/details/114959148----乔霸
6.5.1 事务指令
Redis:multi(标记事务开始)、exec(执行commands队列)、discard(结束事务,并消除commands队列)
6.5.2 事务底层实现
- Redis基于Commands队列实现
6.5.3 事务默认状态
-
Redis默认关闭
-
没开启事务:立即执行并返回结果,直接写入内存
-
开启事务:不会立刻执行,排入队列,并返回队列状态,调用exec才会执行commands中的命令
6.5.4.事务是否支持回滚
6.5.5.事务是否原子性
- mysql事务是原子性的,关系型数据库中的事务都是原子性的
-- 事务开启
BEGIN;
INSERT INTO testmd5(`id`,`name`,`pwd`) VALUES(8,'王m',MD5('123456'));
INSERT INTO testmd5(`id`,`name`,`pwd`) VALUES(8,'王m',MD5('789456'));
COMMIT; -- 提交
[SQL]BEGIN;
受影响的行: 0
时间: 0.001s
[SQL]
INSERT INTO testmd5(`id`,`name`,`pwd`) VALUES(8,'王m',MD5('123456'));
受影响的行: 1
时间: 0.000s
[SQL]
INSERT INTO testmd5(`id`,`name`,`pwd`) VALUES(8,'王m',MD5('789456'));
[Err] 1062 - Duplicate entry '8' for key 'PRIMARY'
- redis命令是原子性的,事务不是原子性的
- 若事务队列中存在命令错误(类似java编译性错误),执行
exec
,所有命令都不会执行 - 若事务中存在语法错误(类似java 1/0的运行时异常),执行
exec
,正确命令会被执行,错误命令抛出异常
6.6 执行事务
- mysql默认开启事务自动提交的
- mysql是默认开启,oracle是默认不开启的
SET autocommit = 0 -- 关闭
SET autocommit = 1 -- 开启默认
-- 手动处理事务先关闭
SET autocommit = 0; -- 关闭自动提交
-- 事务开启
START TRANSACTION -- 标记一个事务的开始,从这个命令之后的sql都在一个事务中
DML
-- 事务结束
-- 提交:持久化(成功)
COMMIT
-- 回滚:回到原来的样子(失败)
ROLLBACK;
SET autocommit = 1 -- 开启自动提交
-- 其他
SAVEPOINT 保存点名; -- 设置一个事务的保存点
ROLLBACK to SAVEPOINT 保存点名; -- 回滚到保存点
RELEASE SAVEPOINT 保存点名; -- 释放保存点
set autocommit = 0;
START TRANSACTION;
UPDATE `account` set `money` = `money`-200 WHERE name = '张三';
UPDATE `account` set `money` = `money`+200 WHERE name = '李四';
COMMIT;
ROLLBACK;
set autocommit = 1;
- sql事务相对于java代码,相当于一段被try{业务代码:commit();}catch(){rollback()}的方法