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 可能别的事务需要使用。放后面等待时间少一点。

相关推荐
小蒜学长16 分钟前
校园社团招新网站的设计与实现(代码+数据库+LW)
java·数据库·spring boot·后端·校园社团招新网站
布莱克6051 小时前
MySQL 增删改查(CRUD)语法详解
数据库·mysql·增删改查
Dovis(誓平步青云)1 小时前
几个方案来回选不定?做一个随时切换的候选推荐页
android·java·服务器·开发语言·javascript·数据库·智能化
2501_933670792 小时前
2027届大数据管理与应用求职数字化转型顾问:项目、SQL、业务理解怎么排优先级
数据库·sql
东方护航数据恢复(深圳)3 小时前
物流案例:勒索病毒 Mallox 加密 ERP 数据库,旧备份 + 残留页重组实录【东方护航数据恢复深圳店】
数据库·数据恢复·勒索病毒·二次开盘·开盘·数据镜像
.Hypocritical.3 小时前
Redis从入门到实战:核心原理、场景落地与避坑指南
数据库·redis·缓存
梦想画家3 小时前
SQLMesh Python 模型入门(二):依赖管理、引擎实战与内存优化
数据库·python·sqlmesh
Omics Pro4 小时前
经典多组学整合算法→商用云平台
数据库·人工智能·算法·机器学习·自然语言处理
xcLeigh4 小时前
【KingbaseES数据库教程】国产化信创背景下的数据库选型与初识
linux·数据库·windows·kes·数据选型
rm -rf * && haha.sh4 小时前
【Linux】Rocky 9.8 操作系统磁盘分区与MySQL数据目录迁移
linux·运维·mysql