mysql--事务四大特性与隔离级别

事务四大特性与隔离级别

mysql事务的概念

事务就是一组操作的集合,他是一个不可分割的整体,事务会把所有的操作作为一个整体一起向系统提交或撤销操作。

事务的属性

  • 原子性(Atomicity)
  • 一致性(Consistency)
  • 隔离性(Isolation)
  • 持久性(Durability)

事务控制语句

  • 查看/设置事务提交
sql 复制代码
START TRANSACTION;
  • 提交一个事务
sql 复制代码
COMMIT;
  • 回滚一个事务
sql 复制代码
ROLLBACK;

1为自动提交,0位手动提交。

msyql默认为自动提交,需要手动设置为手动提交。

执行成功时,进行commit提交事务,程序出时是进行回滚事务

转账示例

sql 复制代码
-- 关闭自动提交
SET AUTOCOMMIT = 0;

-- 开始事务
START TRANSACTION;

-- 查询张三和李四的余额
SELECT balance INTO @zhangsan_balance FROM accounts WHERE name = '张三';
SELECT balance INTO @lisi_balance FROM accounts WHERE name = '李四';

-- 如果张三的余额足够,进行转账操作
IF @zhangsan_balance >= 1000 THEN
    -- 更新张三和李四的余额
    UPDATE accounts SET balance = balance - 1000 WHERE name = '张三';
    UPDATE accounts SET balance = balance + 1000 WHERE name = '李四';
    -- 提交事务
    COMMIT;
    SELECT '转账成功';
ELSE
    -- 回滚事务
    ROLLBACK;
    SELECT '转账失败,张三余额不足';
END IF;

-- 开启自动提交
SET AUTOCOMMIT = 1;

并发事务引发的问题

脏读

脏读(Dirty Read)是指一个事务在读取另一个未提交的事务所做的修改时,产生不一致的结果。具体来说,当一个事务读取了另一个事务未提交的数据,然后这个未提交的数据被回滚了,那么读取到的数据就是脏数据,因为它实际上不应该存在于数据库中。

脏读场景

假设有两个用户:A 和 B。用户 A 有 1000 元,用户 B 有 2000 元。现在 A 从自己的账户中转账 500 元到 B 的账户。

  1. 初始状态

用户 A 的账户余额为 1000 元。

用户 B 的账户余额为 2000 元。

  1. 转账操作

用户 A 开始一个事务,从自己的账户中扣除 500 元。

用户 B 开始一个事务,将 500 元存入自己的账户。

  1. 脏读

用户 B 在事务中读取自己的账户余额,发现账户余额变成了 2500 元(未提交的转账操作)。

用户 A 的转账操作因为某种原因失败,并回滚了。

  1. 结果

用户 B 实际上没有收到任何转账,但是由于脏读,他错误地读取到了自己账户的余额为 2500 元,这是一个不一致的状态。

不可重复读

事务A在第一步查询了id为1的数据,然后事务B修改id为1的数据并且提交了数据,然后事务A在第三步又查询了id为1的数据,发现两次查询的数据不一致。

幻读

幻读(Phantom Read)是并发事务可能遇到的另一种问题,也涉及到事务隔离性。幻读场景指的是在一个事务中多次执行相同的查询,但在不同的查询中返回了不同数量的行。

幻读场景

  • 事务T1执行了一个查询,返回了一组满足某个条件的行。
  • 事务T2插入了一些新的行,这些行也满足了T1查询中的条件,并且提交了事务。
  • 事务T1再次执行相同的查询,但这次返回的结果集比之前多了新插入的行,导致得到了不一致的结果。

事务的隔离级别

对号表示问题会出现,X白表示问题已解决。

串行化·:安全性高,效率低。

读未提交:效率最高,但是安全性最低

读未提交

sql 复制代码
-- 事务T1
START TRANSACTION;

-- 事务T2
START TRANSACTION;

-- T2更新了某行数据
UPDATE table_name SET column1 = new_value WHERE condition;

-- T1读取T2尚未提交的数据
SELECT * FROM table_name WHERE condition;

-- T2提交
COMMIT;

-- T1继续
-- T1读取了已提交的数据
SELECT * FROM table_name WHERE condition;

-- T1提交
COMMIT;

读已提交

sql 复制代码
-- 事务T1
START TRANSACTION;

-- 事务T2
START TRANSACTION;

-- T2更新了某行数据
UPDATE table_name SET column1 = new_value WHERE condition;

-- T2提交
COMMIT;

-- T1读取T2已提交的数据
SELECT * FROM table_name WHERE condition;

-- T1提交
COMMIT;

可重复读(MySQL默认)

sql 复制代码
-- 事务T1
START TRANSACTION;

-- 事务T2
START TRANSACTION;

-- T2更新了某行数据
UPDATE table_name SET column1 = new_value WHERE condition;

-- T2提交
COMMIT;

-- T1再次读取T2修改的数据,但是在可重复读级别下,T1看到的数据仍然是之前启动事务时的快照数据
SELECT * FROM table_name WHERE condition;

-- T1提交
COMMIT;

总结

相关推荐
派可数据BI可视化28 分钟前
商业智能BI 浅谈数据孤岛和数据分析的发展
大数据·数据库·数据仓库·信息可视化·数据挖掘·数据分析
yong999030 分钟前
C#驱动斑马打印机实现包装自动打印
java·数据库·c#
野犬寒鸦1 小时前
从零起步学习MySQL || 第五章:select语句的执行过程是怎么样的?(结合源码深度解析)
java·服务器·数据库·后端·mysql·adb
QT 小鲜肉1 小时前
【个人成长笔记】Qt 中 SkipEmptyParts 编译错误解决方案及版本兼容性指南
数据库·c++·笔记·qt·学习·学习方法
我是苏苏2 小时前
C#高级:数据库中使用SQL作分组处理4(LAG() 偏移函数)
数据库
wudl55662 小时前
股票300394(天孚通信)2025年4月20日
数据库
IvorySQL2 小时前
PostgreSQL 18 中国贡献者经验分享:开源参与的四点建议
数据库·postgresql·开源
曾凡宇先生2 小时前
openEuler安装jdk,nginx,redis
linux·开发语言·数据库·openeuler
点灯小铭3 小时前
基于单片机的四沟道步进电机玉米补种机设计与实现
数据库·单片机·嵌入式硬件·毕业设计·课程设计·期末大作业
清风6666663 小时前
基于单片机的双机串口通信与数字串存储系统设计
数据库·单片机·mongodb·毕业设计·课程设计·期末大作业