前言
1、事务操作有哪些?
2、事务的四大特征是什么?
3、事务的隔离级别(了解)
一、事务是什么?
1、定义: 在实际的开发过程中,一个业务操作如:转账,往往是要多次访问数据库才能完成的。转账是一个用户扣钱,另一个用户加钱。如果其中有一条 SQL 语句出现异常,这条 SQL 就可能执行失败。
(事务执行是一个整体,所有的 SQL 语句都必须执行成功。如果其中有 1 条 SQL 语句出现异常,则所有的SQL 语句都要回滚,整个业务执行失败。)
- 模拟转账交易:张三给李四转 500 元钱
1.首先创建一个数据表
-- 创建数据表
CREATE TABLE account (
id INT PRIMARY KEY AUTO_INCREMENT,
NAME VARCHAR(10),
balance DOUBLE
);
-- 添加数据
INSERT INTO account (NAME, balance) VALUES ('张三', 1000), ('李四', 1000);
2.一个转账的业务操作最少要执行下面的 2 条语句:
张三账号-500
李四账号+500
-- 张三账号-500
update account set balance = balance - 500 where name='张三';
-- 李四账号+500
update account set balance = balance + 500 where name='李四';
3.假设当张三账号上-500 元,服务器崩溃了。李四的账号并没有+500 元,张三账户上的500块钱不翼而飞了,这个时候就是数据出现问题了。
So ~我们需要保证,其中一条 SQL 语句出现问题,整个转账就是失败;只有两条 SQL 都成功了转账才算成功。这个时候就需要用到事务。
二、事务操作
1、手动提交事务
1.执行成功的情况: 开启事务-> 执行多条 SQL 语句 -> 成功提交事务
2.执行失败的情况: 开启事务->执行多条 SQL 语句-> 事务的回滚
语法:
开启事务:start transaction;
提交事务:commit;
回滚事务:rollback;
-
(1)还是刚刚模拟转账的例子1
-
模拟张三给李四转 500 元(成功),张三和李四账户上都有1000块
-
执行以下 SQL 语句: 1.开启事务, 2.张三账号-500, 3.李四账号+500
-
查看 SQLYog 数据库:发现数据并没有改变
-
执行 commit 提交事务
-
查看 SQLYog 数据库:发现数据改变
-
-
(2)转账的例子2
- 模拟张三给李四转 500 元钱(失败),张三和李四账户上都有1000块
- 在控制台执行以下 SQL 语句:1.开启事务, 2.张三账号-500
- SQLYog 查看数据库:发现数据并没有改变
- 执行 rollback 回滚事务
- SQLYog 查看数据库:发现数据没有改变
- 模拟张三给李四转 500 元钱(失败),张三和李四账户上都有1000块
总结: 如果事务中 SQL 语句没有问题,commit 提交事务,会对数据库数据的数据进行改变; 如果事务中 SQL语句有问题,rollback 回滚事务,会回退到开启事务时的状态,钱就不会不翼而飞啦。
2、自动提交事务
- MySQL数据库中事务默认自动提交
- 一条DML(增删改)语句会自动提交一次事务
3、修改事务的默认提交方式
- 查看事务的默认提交方式:SELECT @@autocommit; 1 代表自动提交 0 代表手动提交*
- 修改默认提交方式: set @@autocommit = 0;
三、事务的四大特征
1、原子性
1.定义:每个事务都是一个整体,不可再拆分,事务中所有的 SQL 语句要么都执行成功,要么都失败
2、持久性
1.定义:事务提交或回滚成功后,对数据库的修改是持久的。就算关机,也是保存下来的
3、隔离性
1.定义:多个事务之间相互独立
4、一致性
1.定义:事务在执行前数据库的状态与执行后数据库的状态保持一致。如:转账前2 个人的总金额是 2000 ,转账后 2 个人总金额也是 2000
四、事务的隔离级别
并发操作,多个用户同时访问同一个数据,可能引发并发访问的问题:
1、脏读 :一个事务读取到了另一个事务中尚未提交的数据
2、不可重复读:一个事务中两次读取的数据 内容 不一致
3、幻读:一个事务中两次读取的数据的数量不一致
1、读未提交(read uncommitted)
会出现脏读、不可重复读、幻读的问题
1.打开 A 窗口登录 MySQL,设置全局的隔离级别为最低
mysql -uroot -proot
set global transaction isolation level read uncommitted;
2. 打开 B 窗口,AB 窗口都开启事务
use day23;
start transaction;
3. A 窗口更新 2 个人的账户数据,未提交
update account set balance=balance-500 where id=1;
update account set balance=balance+500 where id=2;
4. B 窗口查询账户
select * from account;
5. A 窗口回滚
rollback;
6. B 窗口查询账户,钱没有到账
2、读已提交(read committed)
1.在 A 窗口设置全局的隔离级别为 read committed
set global transaction isolation level read committed;
2.B 窗口退出 MySQL,B 窗口再进入 MySQL
3.AB 窗口同时开启事务
4.A 更新 2 个人的账户,未提交
update account set balance=balance-500 where id=1;
update account set balance=balance+500 where id=2;
5.B 窗口查询账户
6.A 窗口 commit 提交事务
7.B 窗口查看账户
这个时候会发现一个问题: 解决脏读的问题,出现不可重复读、幻读的问题
3、可重复读(repeatable read)
解决脏读、不可重复的问题,出现幻读的问题,这是数据库MySQL默认的级别
- A 窗口设置隔离级别为: repeatable read
set global transaction isolation level repeatable read;
2. B 窗口退出 MySQL,B 窗口再进入 MySQL
3.AB同时开启事务
start transaction;
4.A 窗口更新数据并提交
update account set balance=balance+500 where id=1;
commit;
5.B窗口查询
select * from account;
4、串行化(serializable )在 MySQL 中无法看到幻读的效果
解决以上脏读、不可重复读、幻读的问题
1.开启 A 窗口
set global transaction isolation level serializable;
2. A 窗口退出 MySQL,A 窗口重新登录 MySQL
start transaction;
select count(*) from account;
3. 再开启 B 窗口,登录 MySQL
4. 在 B 窗口中开启事务,添加一条记录
start transaction; -- 开启事务
insert into account (name,balance) values ('LaoWang', 500);
5.在 A 窗口中 commit 提交事务,B 窗口中 insert 语句会在 A 窗口事务提交后立马运行
6.在 A 窗口中接着查询,发现数据不变
select count(*) from account;
7. B 窗口中 commit 提交当前事务
8. A 窗口就能看到最新的数据
总结:
1、1234级别依次增加,1的隔离级别最低,4的隔离级别最高,隔离级别越高,安全性越高,但是效率越低
2、 数据库查询隔离级别:select @*@tx_isolation;
3、数据库设置隔离级别:set global transaction isolation level 级别字符串;