纯净、安全、绿色的下载网站

首页|软件分类|下载排行|最新软件|IT学院

当前位置:首页IT学院IT技术

mysql事务 mysql事务仔细讲解

奔跑的蜗牛...   2021-12-07 我要评论
想了解mysql事务仔细讲解的相关内容吗奔跑的蜗牛...在本文为您仔细讲解mysql事务的相关知识和一些Code实例欢迎阅读和指正我们先划重点:mysql事务详解,mysql事务实现下面大家一起来学习吧

简介

事务是由一组sql语句组成的逻辑处理单元

事务四个特性

原子性(Atomicity):
	要么都成功要么都失败
	undo log实现
一致性(Consistent):
	如转账前后两个数额总合保持不变
隔离性(lsolation):数据库提供一定的隔离机制保证事务在不受外部并发操作影响的“独立”环境下运行
	锁mvcc多版本并发控制
持久性(Durable):事务提交持久化磁盘
	redo log

事务隔离级别

数据库的事务隔离级别有四种分别是读未提交读已提交可重复读序列化不同的隔离级别会产生脏读幻读不可重复读等相关问题因此在选择隔离级别的时候要根据应用场景来决定使用不同的隔离级别

隔离级别 脏读 不可重复读 幻读
READ-UNCOMMITTED
READ-COMMITED ×
REPEATABLE-READ × ×
SERIALIZABLE × × ×

事务隔离级别带来的问题

脏读(Dirty Reads一个事务访问到了另外一个事务未提交的数据):
	当一个事务正在访问数据并且对数据进行了修改而这种修改还没有提交到数据库中这时另一个事务也访问这个数据然后使用了这个数据
不可重复度(Non-Repeatable Reads 一个事务两次同样的查询查询到了不同的数据):
	一个事务在读取某些数据后的某个时间再次读取以前读过的数据发现和以前读出的数据不一致
	更新删除
幻读(Phantom Reads 一个事务两次同样的查询查询到了不同的数据):
	一个事务按照相同的查询条件重新读取以前查询过的数据却发现其他事务插入了满足其查询条件的新数据
	插入

验证

查看事务的隔离级别show variables like ‘tx_isolation';

查看事务是否自动提交show variables like ‘autocommit';

关闭自动提交事务=0|OFF

set autocommit = 0;

脏读:

设置事务隔离级别A、B
	set session transaction isolation level read uncommitted;
sessionA
开启事务
	start transaction;
插入一条数据
	INSERT INTO `db_test`.`t_user`(`id`, `name`) VALUES (5, 'DuQi');
sessionB
另一个连接进行查询
	select * from t_user;
	+----+----------+
	| id | name     |
	+----+----------+
	|  1 | ZhangSan |
	|  2 | LiSi     |
	|  3 | WangWu   |
	|  4 | LaoWang  |
	|  5 | DuQi     |
	+----+----------+
	此时连接B查询到连接A未提交的事务的记录id为5
	
到这里验证了一个session读取到了另一个事务未提交的数据

不可重复读:

修改事务隔离级别
	set session transaction isolation level read committed;
A开启事务
	start transaction;
验证更新
	B执行查询语句
		MySQL [db_test]> select * from t_user;
		+----+----------+
		| id | name     |
		+----+----------+
		|  1 | ZhangSan |
		|  2 | LiSi     |
		|  3 | WangWu   |
		|  4 | LaoWang  |
		|  5 | DuQi     |
		+----+----------+
	A执行更新语句
		update t_user set name = 'duqi' where id = 5;
	B执行查询语句
		start transaction;
		MySQL [db_test]> select * from t_user;
		+----+----------+
		| id | name     |
		+----+----------+
		|  1 | ZhangSan |
		|  2 | LiSi     |
		|  3 | WangWu   |
		|  4 | LaoWang  |
		|  5 | DuQi     |
		+----+----------+
	A提交事务
		commit;
	B执行查询语句(同一个事务两次查询结果不一致)
		MySQL [db_test]> select * from t_user;
		+----+----------+
		| id | name     |
		+----+----------+
		|  1 | ZhangSan |
		|  2 | LiSi     |
		|  3 | WangWu   |
		|  4 | LaoWang  |
		|  5 | duqi     |
		+----+----------+
继续验证删除
	A 开启事务 B开启事务
		start transaction ;
	A删除一条记录
		delete from t_user where id = 5;
	B事务查询正常查询被删除的记录还在
		MySQL [db_test]> select * from t_user;
		+----+----------+
		| id | name     |
		+----+----------+
		|  1 | ZhangSan |
		|  2 | LiSi     |
		|  3 | WangWu   |
		|  4 | LaoWang  |
		|  5 | DuQi     |
		+----+----------+
	A commit;
	B 继续查询 发现同一事物中多次查询结果不一致
		MySQL [db_test]> select * from t_user;
		+----+----------+
		| id | name     |
		+----+----------+
		|  1 | ZhangSan |
		|  2 | LiSi     |
		|  3 | WangWu   |
		|  4 | LaoWang  |
		+----+----------+

验证插入
	A、B 开启事务
		start transaction;
	A 插入记录
		INSERT INTO `db_test`.`t_user`(`id`, `name`) VALUES (5, 'DuQi');
	B进行查询
		MySQL [db_test]> select * from t_user;
		+----+----------+
		| id | name     |
		+----+----------+
		|  1 | ZhangSan |
		|  2 | LiSi     |
		|  3 | WangWu   |
		|  4 | LaoWang  |
		+----+----------+	
	A提交事务
		commit;
	B查询 也是能查询到A提交的事务
		MySQL [db_test]> select * from t_user;
		+----+----------+
		| id | name     |
		+----+----------+
		|  1 | ZhangSan |
		|  2 | LiSi     |
		|  3 | WangWu   |
		|  4 | LaoWang  |
		|  5 | DuQi     |
		+----+----------+

幻读:

修改事务隔离级别
	set session transaction isolation level repeatable read;
A、B开启事务
	start transaction;
A插入一条数据	
	INSERT INTO `db_test`.`t_user`(`id`, `name`) VALUES (5, 'DuQi');
B查询
	MySQL [db_test]> select * from t_user;
	+----+----------+
	| id | name     |
	+----+----------+
	|  1 | ZhangSan |
	|  2 | LiSi     |
	|  3 | WangWu   |
	|  4 | LaoWang  |
	+----+----------+
A提交事务
	commit;
B事务查询
	MySQL [db_test]> select * from t_user;
	+----+----------+
	| id | name     |
	+----+----------+
	|  1 | ZhangSan |
	|  2 | LiSi     |
	|  3 | WangWu   |
	|  4 | LaoWang  |
	|  5 | DuQi     |
	+----+----------+
可能发现不同事务之间插入是可以查询到的

咱们再继续验证更新和删除
	A、B开启事务
	A更新 update t_user set name = 'duqi' where id = 5;
	B查询
		MySQL [db_test]> select * from t_user;
		+----+----------+
		| id | name     |
		+----+----------+
		|  1 | ZhangSan |
		|  2 | LiSi     |
		|  3 | WangWu   |
		|  4 | LaoWang  |
		|  5 | DuQi     |
		+----+----------+	
	A提交事务commit
	B继续查询
		MySQL [db_test]> select * from t_user;
		+----+----------+
		| id | name     |
		+----+----------+
		|  1 | ZhangSan |
		|  2 | LiSi     |
		|  3 | WangWu   |
		|  4 | LaoWang  |
		|  5 | DuQi     |
		+----+----------+
	咱们再继续验证删除
		A、B开启事务
		A事务执行删除操作 delete from t_user where id = 5;
		B事务执行查询
			MySQL [db_test]> select * from t_user;
			+----+----------+
			| id | name     |
			+----+----------+
			|  1 | ZhangSan |
			|  2 | LiSi     |
			|  3 | WangWu   |
			|  4 | LaoWang  |
			|  5 | duqi     |
			+----+----------+
		A提交事务B继续查询
			MySQL [db_test]> select * from t_user;
			+----+----------+
			| id | name     |
			+----+----------+
			|  1 | ZhangSan |
			|  2 | LiSi     |
			|  3 | WangWu   |
			|  4 | LaoWang  |
			|  5 | duqi     |
			+----+----------+
可能大家会发现REPEATABLE-READ 事务隔离级别解决了删除和更新的问题但是插入的问题一直存在		

MVCC

多版本并发控制MVCC是一种并发控制的方法一般在数据库管理系统中实现对数据库的并发访问在编程语言中实现事务内存

mvcc在Mysql INNODB中的实现主要是为了提高数据库并发性能用更好的方式去处理读写冲突做到即使有读写冲突时也能做到不加锁非阻塞并发读

了解mvcc之前首先要了解两个概念什么是当前读什么是快照读

当前读

读取最新版本的数据

像select lock in share mode(共享锁)select for update;update、insert、delete(排他锁)这些操作都是一种当前读
为什么叫当前读?
	就是它读取的是记录的最新版本读取时还要保证其他并发事务不能修改当前记录会对读取的记录进行加锁

快照读

读取历史版本的数据

像不加锁的select操作就是快照读既不加锁的非阻塞读;
快照读的前提是隔离级别不是串行级别串行级别下的快照读会退化成当前读;
之所以出现快照读的情况是基于提高并发性能的考虑快照读的实现是基于多版本控制并发控制既MVCC可以认为mvcc是行锁的一个变种但它在很多情况下避免了加锁操作降低了开销;

当前读、快照读、MVCC关系

MVCC多版本并发控制指的是维持一个数据的多个版本使得读写操作没有冲突快照读是mysql为实现mvcc的一个非阻塞读功能
mvcc模块在Mysql中的具体实现是由三个隐式字段undo日志readview三个组件来实现的

这里补充一点:三个隐式字段中其中有一个是列的唯一标志有些同学设计表的时候一定要加主键(列依赖主键)即使它几乎无用处也要加上其实对于配置表几乎不进行增删操作的表完全没必要加主键mysql在插入数据的时候会进行判断表有无主键如果有主键会使用主键作为唯一标示如果没有主键会自动生成7byte大小的主键所以表的合理性要根据不用使用场景进行设计

mvcc 解决的问题

并发场景

1、读读:不存在任何问题也不需要并发控制
2、读写:有线程安全问题可能会造成事务隔离级别问题可能遇到脏读、不可重复读、幻读
3、写写:有线程安全问题可能存在更新丢失问题

解决的问题

1、在并发读写数据库时可以做到在读操作时不用阻塞写操作写操作也不用阻塞读操作提高了数据库并发读写的性能
2、解决脏读、幻读、不可重复读等事务隔离问题但是不能解决更新丢失问题

MVCC实现原理

mvcc的实现原理主要依赖于记录中的三个隐藏字段、undologread view来实现的

隐藏字段

行记录除了我们自定义的字段外还有数据库隐式定义的DB_TRX_ID,BD_ROLL_PTR,DB_ROW_ID等字段

DB_TRX_ID 最近修改事务id:
	6字节,记录创建这条记录或者最后一次修改该记录的事务id
DB_ROLL_PTR 回滚指针:
	7字节指向这条记录的上一个版本用于配合undolog指向上一个旧版本
DB_ROW_ID 隐藏主键:
	6字节如果数据库表没有主键那么innodb会自动生成一个6字节的row_id

undo log

undo log被称之为回滚日志表示进行insertdeleteupdate操作的时候产生的方便回滚日志

当进行insert操作的时候产生的undo log只在事务回滚的时候需要并且在事务提交之后可以被立刻丢弃
当进行update和delete操作的时候产生的undo log不仅仅在事务回滚的时候需要在快照读的时候也需要所以不能随便删除只有在快照读或事务回滚不涉及该日志时对应的日志才会被purge线程统一清除(当数据发生更新和删除操作的时候都只是设置一下老记录如果某个记录的deleted_id为true并且DB_TRX_ID相对于purge线程的read view可见那么这条记录一定可以被清除的)

原理

当进行insert操作时会生成对应delete语句
当进行delete操作时会备份原数据的insert语句
当进行update时会记录原数据的update语句
这样操作方便记录回滚

read View

READ View是事务进行快照读操作的时候产生的读视图在该事务执行快照的那一刻会生成一个数据系统当前的快照记录并维护系统当前活跃事务的id事务的id值是递增的

DB_ROW_ID DB_TRX_ID DB_ROLL_PTR c_name i_age
1 1 zhangsan1 18
2 2 1 zhangsan2 19
READ VIEW的最大作用是用来做可见性判断的也就是说当某个事务在执行快照读的时候对该记录创建一个Read View的视图把它当作条件去判断当前事务能够看到哪个版本的数据有可能读取到的是最新的数据也有可能读取到的是最新的数据也有可能读取的是当前记录的undolog中某个版本的数据
read view遵循的可见性算法主要是将要被修改的数据的最新记录中的DB_TRX_ID取出来与系统当前其他活跃事务的id去对比如果DB_TRX_ID跟READ VIEW的属性做了比较不符合可见性那么就通过DB_ROLL_PTR回滚指针去取出undolog中的DB_TRX_ID做比较既遍历链表中的DB_TRX_ID,直到找到满足条件的DB_TRX_ID,这个DB_TRX_ID所在的旧记录就是当前事务能看到的最新老版本数据

可见性规则

了解可见性规则之前首先要了解下Read View中的三个全局属性

trx_list:
	一直数值列表用来维护Read View生成时刻系统正活跃的事务ID
up_limit_id:
	记录trx_list列表中事务ID的最小ID
low_limit_id:
	Read View生成时刻系统尚未分配下一个事务ID

比较规则

1、首先判断DB_TRX_ID < up_limit_id,如果小于则当前事务能看到DB_TRX_ID所在的记录如果大于等于进入下一个判断
2、判断DB_TRX_ID >= low_limit_id,如果大于等于则代表DB_TRX_ID所在的记录在Read View生成后才出现的那么对于当前事务肯定不可见如果小于进入下一步判断
3、判断DB_TRX_ID是否在活跃事务中如果在则代表在Read View生成时刻这个事务还是活跃状态还没有commit修改的数据当前事务也是看不到如果不在则说明这个事务在Read View生成之前就已经开始commit那么修改的结果是能够看到的

相关文章

猜您喜欢

  • Vue之MVVM,模板语法和数据绑定 Vue基础之MVVM,模板语法和数据绑定

    想了解Vue基础之MVVM,模板语法和数据绑定的相关内容吗永远没有404在本文为您仔细讲解Vue之MVVM,模板语法和数据绑定的相关知识和一些Code实例欢迎阅读和指正我们先划重点:VueMVVM,Vue模板语法,Vue数据绑定下面大家一起来学习吧..
  • C++ STL红黑树实现 C++ STL容器详解之红黑树部分模拟实现

    想了解C++ STL容器详解之红黑树部分模拟实现的相关内容吗TT在长大在本文为您仔细讲解C++ STL红黑树实现的相关知识和一些Code实例欢迎阅读和指正我们先划重点:C++ 红黑树,C++ STL红黑树,C++ STL红黑树实现下面大家一起来学习吧..

网友评论

Copyright 2020 www.eleasoftware.com 【绿软下载站】 版权所有 软件发布

声明:所有软件和文章来自软件开发商或者作者 如有异议 请与本站联系 点此查看联系方式