MySQL事务
文章目录
1.事务的概念
- 一条或多条 SQ L 语句组成一个执行单元,其特点是这个单元要么同时成功要么同时失败,单元中的每条 SQ L 语句都相互依赖,形成一个整体,如果某条 SQ L 语句执行失败或者出现错误,那么整个单元就会回滚,撤回到事务最初的状态,如果单元中所有的 SQ L 语句都执行成功,则事务就顺利执行。
2.事务的演示
数据准备
-- 创建qian数据库
CREATE DATABASE qian;
-- 使用qian数据库
USE qian;
-- 创建账户表
CREATE TABLE account(
id INT PRIMARY KEY AUTO_INCREMENT, -- 账户id
NAME VARCHAR(20), -- 账户名称
money DOUBLE -- 账户余额
);
-- 添加数据
INSERT INTO account VALUES (NULL,'tom',1000),(NULL,'jack',1000);
未使用事务实例
-- Tom的账户-200
UPDATE account set money=money-200 where NAME='tom';
出错了...
-- Jack的账户+200
UPDATE account set money=money+200 WHERE NAME='jack';
由于4行有错误,所以只执行了第一条SQL语句,第二条没有执行。使得转账出现了错误。
管理事务的演示
-
操作事务三个步骤
- 开启事务:记录回滚点,通知服务器,所要执行的一组操作,要么同时成功,要么同时失败。
- 执行一条或多条SQL语句。
- 结束事务(提交或回滚事务)
- 提交:没有错误,提交事务,将数据持久化。
- 回滚:出现问题,回滚事务,数据恢复到开启事务时的状态。
-
开启事务
-- 开启事务
START TRANSACTION
- 回滚事务
-- 回滚事务
ROLLBACK;
- 提交事务
-- 提交事务
COMMIT;
使用事务实例
-- 开启事务
START TRANSACTION
-- Tom的账户-200
UPDATE account set money=money-200 where NAME='tom';
-- 出错了...
-- Jack的账户+200
UPDATE account set money=money+200 WHERE NAME='jack';
-- 回滚事务
ROLLBACK;
-- 提交事务
COMMIT;
提交事务的方式
-
提交方式
- 自动提交(MySQL数据库默认)
- 手动提交
-
修改提交方式
-
查看提交方式
-- 查看事务的提交方式 SELECT @@AUTOCOMMIT
-
修改提交方式
-- 标准语法 SET @@AUTOCOMMIT=数字; -- 修改为手动提交 SET @@AUTOCOMMIT=0; -- 修改为自动提交 set @@AUTOCOMMIT=1;
-
3.事务的四大特征
- 原子性(atomicity)
- 原子性是指事务包含的所有操作要么全部成功,要么全部失败回滚,因此事务的操作如果成功就必须要完全应用到数据库,如果操作失败则不能对数据库有任何影响
- 一致性(consistency)
- 一致性是指事务必须使数据库从一个一致性状态变换到另一个一致性状态,也就是说一个事务执行之前和执行之后都必须处于一致性状态
- 拿转账来说,假设Tom和Jack两者的钱加起来一共是2000,那么不管A和B之间如何转账,转几次账,事务结束后两个用户的钱相加起来应该还得是2000,这就是事务的一致性
- 隔离性(isolcation)
- 隔离性是当多个用户并发访问数据库时,比如操作同一张表时,数据库为每一个用户开启的事务,不能被其他事务的操作所干扰,多个并发事务之间要相互隔离
- 持久性(durability)
- 持久性是指一个事务一旦被提交了,那么对数据库中的数据的改变就是永久性的,即便是在数据库系统遇到故障的情况下也不会丢失提交事务的操作
4.事务的隔离级别
-
隔离级别的概念
- 多个客户端操作时 ,各个客户端的事务之间应该是隔离的,相互独立的 , 不受影响的。
- 而如果多个事务操作同一批数据时,则需要设置不同的隔离级别 , 否则就会产生问题
-
四种隔离级别
1 读未提交 read uncommitted 2 读已提交 read committed 3 可重复读 repeatable read 4 串行化 serializable -
可能引发的问题
问题 现象 脏读 是指在一个事务处理过程中读取了另一个未提交的事务中的数据 , 导致两次查询结果不一致 不可重复读 是指在一个事务处理过程中读取了另一个事务中修改并已提交的数据, 导致两次查询结果不一致 幻读 select 某记录是否存在,不存在,准备插入此记录,但执行 insert 时发现此记录已存在,无法插入。或不存在执行delete删除,却发现删除成功
-
-
查询数据库隔离级别
-- 查询事务的隔离级别 SELECT @@tx_isolation;
-
修改数据库隔离级别
-- 标准语法 SET GLOBAL TRANSACTION ISOLATION LEVEL 级别字符串; -- 修改数据库隔离级别为read uncommitted SET GLOBAL TRANSACTION ISOLATION LEVEL read uncommitted; -- 查看隔离级别 SELECT @@TX_ISOLATION; -- 修改后需要断开连接重新开
5.事务的隔离级别演示
我们在进行演示时,需要开启两个数据库窗口,用来表示两个用户
-
脏读问题
-
窗口1
-- 查询账户表 select * from account; -- 设置隔离级别为read uncommitted set global transaction isolation level read uncommitted; -- 开启事务 start transaction; -- 转账 update account set money = money - 500 where id = 1; update account set money = money + 500 where id = 2; -- 窗口2查询转账结果 ,出现脏读(查询到其他事务未提交的数据) -- 窗口2查看转账结果后,执行回滚 rollback;
-
窗口2
-- 查询隔离级别 select @@tx_isolation; -- 开启事务 start transaction; -- 查询账户表 select * from account;
-
-
解决脏读的问题和演示不可重复读的问题
-
窗口1
-- 设置隔离级别为read committed set global transaction isolation level read committed; -- 开启事务 start transaction; -- 转账 update account set money = money - 500 where id = 1; update account set money = money + 500 where id = 2; -- 窗口2查看转账结果,并没有发生变化(脏读问题被解决了) -- 执行提交事务。 commit; -- 窗口2查看转账结果,数据发生了变化(出现了不可重复读的问题,读取到其他事务已提交的数据)
-
窗口2
-- 查询隔离级别 select @@tx_isolation; -- 开启事务 start transaction; -- 查询账户表 select * from account;
-
-
解决不可重复读的问题
-
窗口1
-- 设置隔离级别为repeatable read set global transaction isolation level repeatable read; -- 开启事务 start transaction; -- 转账 update account set money = money - 500 where id = 1; update account set money = money + 500 where id = 2; -- 窗口2查看转账结果,并没有发生变化 -- 执行提交事务 commit; -- 这个时候窗口2只要还在上次事务中,看到的结果都是相同的。只有窗口2结束事务,才能看到变化(不可重复读的问题被解决)
-
窗口2
-- 查询隔离级别 select @@tx_isolation; -- 开启事务 start transaction; -- 查询账户表 select * from account; -- 提交事务 commit; -- 查询账户表 select * from account;
-
-
幻读的问题
-
窗口1
-- 设置隔离级别为repeatable read set global transaction isolation level repeatable read; -- 开启事务 start transaction; -- 添加一条记录 INSERT INTO account VALUES (3,'王五',1500); -- 查询账户表,本窗口可以查看到id为3的结果 SELECT * FROM account; -- 提交事务 COMMIT;
-
窗口2
-- 查询隔离级别 select @@tx_isolation; -- 开启事务 start transaction; -- 查询账户表,查询不到新添加的id为3的记录 select * from account; -- 添加id为3的一条数据,发现添加失败。出现了幻读 INSERT INTO account VALUES (3,'测试',200); -- 提交事务 COMMIT; -- 查询账户表,查询到了新添加的id为3的记录 select * from account;
-
-
解决幻读的问题
-
窗口1
-- 设置隔离级别为serializable set global transaction isolation level serializable; -- 开启事务 start transaction; -- 添加一条记录 INSERT INTO account VALUES (4,'赵六',1600); -- 查询账户表,本窗口可以查看到id为4的结果 SELECT * FROM account; -- 提交事务 COMMIT;
-
窗口2
-- 查询隔离级别 select @@tx_isolation; -- 开启事务 start transaction; -- 查询账户表,发现查询语句无法执行,数据表被锁住!只有窗口1提交事务后,才可以继续操作 select * from account; -- 添加id为4的一条数据,发现已经存在了,就不会再添加了!幻读的问题被解决 INSERT INTO account VALUES (4,'测试',200); -- 提交事务 COMMIT;
-
6.隔离级别总结
隔离级别 | 名称 | 出现脏读 | 出现不可重复读 | 出现幻读 | 数据库默认隔离级别 | |
---|---|---|---|---|---|---|
1 | read uncommitted | 读未提交 | 是 | 是 | 是 | |
2 | read committed | 读已提交 | 否 | 是 | 是 | Oracle / SQL Server |
3 | repeatable read | 可重复读 | 否 | 否 | 是 | MySQL |
4 | **serializable ** | 串行化 | 否 | 否 | 否 |
注意:隔离级别从小到大安全性越来越高,但是效率越来越低 , 所以不建议使用READ UNCOMMITTED 和 SERIALIZABLE 隔离级别。
7.事务的总结
- 一条或多条 SQL 语句组成一个执行单元,其特点是这个单元要么同时成功要么同时失败。例如转账操作
- 开启事务:start transaction;
- 回滚事务:rollback;
- 提交事务:commit;
- 事务四大特征
- 原子性
- 持久性
- 隔离性
- 一致性
- 事务的隔离级别
- read uncommitted(读未提交)
- read committed (读已提交)
- repeatable read (可重复读)
- serializable (串行化)