MySQL是广泛使用的关系型数据库管理系统,它支持事务处理,确保数据操作的一致性和可靠性。本文将介绍MySQL事务的基本概念和重要性。
事务:是一组操作的集合,它是一个不可分割的工作单位,事务会把所有的操作作为一个整体一起向系统提交或撤销操作请求,即这些操作要么同时成功,要么同时失败。
我们现在就拿一个经典的银行存取钱例子来说明: 李四给王五转账500块钱,李四银行账户就要减少500,并且王五账户要增加500。这一组操作就必须在一个事务范围内,要么转账同时成功,要么转账同时失败
id | name | money |
1 | 李四 | 2000 |
2 | 王五 | 2000 |
转账分为以下情况:
1.正常情况:转账成功,可以分为以下基本三步完成,完成之后李四减少500,王五增加500,转账成功:
图片
最终数据库结果:
id | name | money |
1 | 李四 | 1500 |
2 | 王五 | 2500 |
2.异常情况:转账失败,耶斯分为三步完成,假设李四减少500块钱以后,王五账户金额没有发生变化,这就造成了严重的数据不一致问题。
图片
问题解决方式:通过事务完成,我们在执行业务逻辑之前开启事务,业务执行完毕后,关闭事务。如果执行过程中出错,则事务回滚,将数据恢复到事务开启之前状态。
图片
注意: 默认MySQL的事务是自动提交的,也就是说,当执行完一条DML语句时,MySQL会立即隐 式的提交事务。
如果您觉得本文不错,欢迎关注,点赞,收藏支持,您的关注是我坚持的动力!
通过sql语句,实现刚才的例子。
-- 创建数据库test
create database if not exists test;
use test;
-- 删除表
drop table if exists tb_account;
create table tb_account(
id int primary key AUTO_INCREMENT comment 'ID',
name varchar(10) comment '姓名',
money double(10,2) comment '余额'
) comment '账户表';
insert into tb_account(name, money) VALUES ('李四',2000), ('王五',2000);
-- 正常转账情况
-- 1. 查询李四余额
select * from tb_account where name = '李四';
-- 2. 李四的余额减少500
update tb_account set money = money - 500 where name = '李四';
-- 3. 王五的余额增加500
update tb_account set money = money + 500 where name = '王五';
-- 4. 查看账户结果
select * from tb_account;
测试完毕之后检查数据的状态, 可以看到数据操作前后是一致的。
图片
-- 转账异常情况
-- 1. 查询李四余额
select * from tb_account where name = '李四';
-- 2. 李四的余额减少500
update tb_account set money = money - 500 where name = '李四';
出错了....
-- 3. 王五的余额增加500
update tb_account set money = money + 500 where name = '王五';
-- 4. 查看账户结果
select * from tb_account;
我们把数据都恢复到2000, 然后再次一次性执行上述的SQL语句(出错了.... 这句话不符合SQL语 法,执行就会报错),检查最终的数据情况, 发现数据在操作前后不一致了。
图片
1.开启事务
-- 1.开启事务
start transaction 或者 BEGIN;
2.提交事务
-- 2.提交事务
commit;
3.事务回滚
-- 3.事务回滚
rollback ;
转账案例
-- 开启事务
start transaction;
-- 1. 查询李四余额
select * from tb_account where name = '李四';
-- 2. 李四的余额减少1000
update tb_account set money = money - 500 where name = '李四';
-- 如果转账失败 执行rollback
-- 3. 王五的余额增加1000
update tb_account set money = money + 500 where name = '王五';
-- 如果正常执行完毕, 则提交事务
commit;
-- 如果执行过程中报错, 则回滚事务
-- rollback;
MySQL事务遵循ACID属性,即原子性、一致性、隔离性和持久性。
SQL 标准中定义了四种隔离级别,分别是:
事务隔离级别,是为了解决多个并行事务竞争导致的数据安全问题的一种规范。具体来说,多个事务竞争可能会产生三种不同的现象。
脏读:一个事务读到另外一个事务还没有提交的数据
图片
示例sql:
1.事务A 中SQL
-- 步骤一:设置事务A隔离级别 读未提交
SET SESSION TRANSACTION ISOLATION LEVEL READ UNCOMMITTED;
use test;
-- 步骤三:开启事务A,查询ID=1的数据
start transaction;
select * from tb_account where id=1;
-- 步骤五:开启事务A,查询ID=1的数据
select * from tb_account where id=1;
commit ;
2.事务B中SQL
-- 步骤二:设置事务B隔离级别 读未提交
SET SESSION TRANSACTION ISOLATION LEVEL READ UNCOMMITTED;
use test;
-- 步骤四:开启事务A,
start transaction;
-- 更新ID=1的数据 mnotallow=money-500
update tb_account set mnotallow=money-500 where id=1;
commit ;
图片
不可重复读:一个事务先后读取同一条记录,但两次读取的数据不同,称之为不可重复读
图片
示例sql:
1.事务A 中SQL
-- 读已提交隔离级别下 不可重复读
-- 步骤一:设置事务A隔离级别 读已提交
SET SESSION TRANSACTION ISOLATION LEVEL READ COMMITTED;
use test;
-- 步骤三:开启事务A,查询ID=1的数据
start transaction;
select * from tb_account where id=1;
-- 步骤六:事务A,查询ID=1的数据
select * from tb_account where id=1;
-- 步骤八:事务A,查询ID=1的数据
select * from tb_account where id=1;
commit ;
2.事务B中SQL
-- 读已提交隔离级别下 不可重复读
-- 步骤二:设置事务B隔离级别 读已提交
SET SESSION TRANSACTION ISOLATION LEVEL READ COMMITTED;
use test;
-- 步骤四:开启事务B,更新ID=1的数据 mnotallow=money-500
start transaction;
update tb_account set mnotallow=money-500 where id=1;
-- 步骤五:事务B查询id=1数据
select * from tb_account where id=1;
-- 步骤七:事务B 提交事务 并查询结果
commit ;
select * from tb_account where id=1;
图片
幻读:一个事务按照条件查询数据时,没有对应的数据行,但是在插入数据时,又发现这行数据 已经存在,好像出现了 "幻影"。
图片
示例sql:
1.事务A 中SQL
-- 可重复读隔离级别下 幻读
-- 步骤一:设置事务A隔离级别 可重复读
SET SESSION TRANSACTION ISOLATION LEVEL REPEATABLE READ;
use test;
-- 步骤三:开启事务A,查询ID>1的数据
start transaction;
select * from tb_account where id>1;
-- 步骤五:事务A,查询ID>1的数据
select * from tb_account where id>1;
-- 步骤七:事务A,查询ID>1的数据
select * from tb_account where id>1;
commit ;
2.事务B中SQL
-- 可重复读隔离级别下 幻读
-- 步骤二:设置事务B隔离级别 可重复读
SET SESSION TRANSACTION ISOLATION LEVEL REPEATABLE READ;
use test;
-- 步骤四:开启事务B,插入一条数据
start transaction;
insert into tb_account values(3,'张三',2000);
-- 步骤六:提交事务B
commit ;
图片
隔离级别 | 脏读 | 不可重复读 | 幻读 |
读未提交(Read Uncommitted) | ✔ | ✔ | ✔ |
读已提交(Read Committed) | ✗ | ✔ | ✔ |
可重复读(Repeatable Read) | ✗ | ✗ | ✔ |
串行化(Serializable) | ✗ | ✗ | ✗ |
查看事务隔离级别
SELECT @@TRANSACTION_ISOLATION;
设置事务隔离级别
SET [ SESSION | GLOBAL ] TRANSACTION ISOLATION LEVEL { READ UNCOMMITTED |
READ COMMITTED | REPEATABLE READ | SERIALIZABLE }
注意:事务隔离级别越高,数据越安全,但是性能越低。