MYSQL事务实现原理

文章目录

1、事务的隔离级别
隔离级别 解决问题 备注
读未提交 脏读 可以查询到其他事务未提交的数据。
读已提交 RC 不可重复读(1、乐观锁 加版本号解决脏写 2、行锁 --悲观锁 解决脏写 ) 只能读到其他事务已经提交的数据。
可重复读 RR 幻读 读操作需要加事务,写操作加写事务保证可重复读。如果不加事务就是读已提交
串行化 解决上面所有问题 包括脏写 实现原理:select 加读锁 。 update 加 写锁。
名称 描述
脏读(Dirty Reads) 事务A读取到了事务B已经修改但尚未提交的数据
不可重读(Non-Repeatable Reads) 事务A内部的相同查询语句在不同时刻读出的结果不一致
幻读 事务A读取到了事务B提交的新增数据
脏写 当两个或多个事务选择同一行数据修改,有可能发生更新丢失问题,即最后的更新覆盖了由其他事务所做的更新。
解决脏写 (1)RR 、RC 数据库级别updaet (2) 串行化
2、可重复读详解

(1) 可重复读并发修改问题
描述 :事务A 读到 lilei 1500 后,事务B 修改Leilei 2000 , java中为leilei 加500 ,此时 ,是1500 + 500 =2000 , 应该是2500。

(2) 可重复读原理描述

当事务执行第一条SQL语句时,之后所有的读操作 都是读数据库当时的数据。相当于读快照(readview)。 但是修改操作还是取数据库最新版本做操作。

之后如果执行update where id = 1 ; 语句的话,再查 id =1; 就是修改后的数据。此时因为有行锁其他事务无法修改 id=1的数据

总结:可重复读所有的查询都是快照读,更新都是当前读。

3、MVCC多版本并发控制机制

RR、RC原理详解:

根据回滚指针 (insert 语句 id=1 指向 undo log delete id =1 )

如果需要回滚事务 , 直接执行 undo log delete id =1。

id name balance trx_id (事务ID ) roll_pointer(回滚指针)
1 lilei 0 1 insert undo log
1 lilei 500 2 指向 上一行 id=1 commited
1 lilei 800 3 commited
1 lilei 1000 4 commited

事务A RR

事务 2 commited

select * from account where id = 1 ; ----> 500

事务 3 commited 去查还是 500

事务 4 还未提交 去查还是 500

事务B RC

事务 2 commited

select * from account where id = 1 ; ----> 500

事务 3 commited 去查是 800

事务 4 还未提交 去查 是800

4、锁机制

(1)乐观锁:读已提交隔离级别下使用。

读锁(共享锁、S锁):select ... lock in share mode; (一般的select 都不会加锁)

(2) 读锁是共享的,多个事务可以同时读取同一个资源,但不允许其他事务修改

(3)写锁(排它锁、X锁):select ... for update;

写锁是排他的,会阻塞其他的写锁和读锁,update、delete、insert都会加写锁
MYSQL锁机制详解

5、面试刨析:查询操作方法需要使用事务吗?

(1) 一条 select 不需要

(2) 2 或多条 select

看隔离级别 RR 下 , 加 readolne = true (读事务) 可以保证数据再同一时间维度下。

RC 下, 读到的是最新的数据。 读操作没必要加事务。

6、持久性:一旦提交了事务,它对数据库的改变就应该是永久性的。持久性由redo log日志来实现。

MYSQL事务持久性详解

结尾

事务隔离级别演示

复制代码
	CREATE TABLE `account` (
 `id` int(11) NOT NULL AUTO_INCREMENT,
  `name` varchar(255) DEFAULT NULL,
  `balance` int(11) DEFAULT NULL,
  PRIMARY KEY (`id`)
  ENGINE=InnoDB DEFAULT CHARSET=utf8;
  INSERT INTO `test`.`account` (`name`, `balance`) VALUES ('lilei', '450');
  INSERT INTO `test`.`account` (`name`, `balance`) VALUES ('hanmei', '16000');
  INSERT INTO `test`.`account` (`name`, `balance`) VALUES ('lucy', '2400');

BEGIN 
set tx_isolation='read‐uncommitted';
set tx_isolation='read‐committed';
set tx_isolation='repeatable‐read';
set tx_isolation='serializable';
COMMIT;

update 放 insert后会好一点。

update 可能别的事务需要使用。放后面等待时间少一点。

相关推荐
牛大兵几秒前
机顶盒获取局域网已经使用IP,开放的端口号,扫描摄像头,NAS,共享主机等开机自启局域网全量扫描工具
数据库·网络协议·tcp/ip
知行产研5 分钟前
中国矿山无人驾驶出海的三重门
数据库·mysql·php
l12586536 分钟前
# RAG低延迟架构设计:从5秒到500ms的优化全链路
数据库·人工智能·python·langchain
RisunJan39 分钟前
Linux命令-vgdisplay(显示卷组详细属性)
linux·运维·数据库
爱和冰阔落1 小时前
【MySQL 慢查询排查实战】列表接口逐渐变慢时,怎样从请求链路定位原因
android·数据库·mysql
JacksonMx1 小时前
企业级 JPA 与数据库架构落地指南
数据库·数据库架构
Dxy12393102161 小时前
MySQL有哪些锁?InnoDB锁体系完整梳理博客
数据库·mysql
wear工程师2 小时前
MySQL 索引条件下推是什么?Using index condition 并不是覆盖索引
sql·mysql
蒸蒸yyyyzwd2 小时前
cpp选手秋招学习笔记 day12
笔记·学习·oracle
Wang's Blog2 小时前
PostgreSQL笔记38:慢查询定位与优化的系统方法论
数据库·笔记·postgresql