mysql事务详细介绍

目录
  • 简介
  • 事务四个特性
  • 事务隔离级别
    • 验证
  • MVCC
    • 当前读
    • 快照读
    • 当前读、快照读、MVCC关系
    • mvcc 解决的问题
    • MVCC实现原理
    • 可见性规则

简介

事务是由一组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的实现原理主要依赖于记录中的三个隐藏字段、undolog,read 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被称之为回滚日志,表示进行insert,delete,update操作的时候产生的方便回滚日志

当进行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,那么修改的结果是能够看到的。

到此这篇关于mysql事务详细介绍的文章就介绍到这了,更多相关mysql事务内容请搜索我们以前的文章或继续浏览下面的相关文章希望大家以后多多支持我们!

(0)

相关推荐

  • MySQL 数据库 索引和事务

    目录 1. 索引 1.1 概念 1.2 作用 1.3 索引的原理 1.3.1 减少磁盘的访问次数是构建索引的核心思想 1.3.2 B+ 树适用实现索引的底层 1.4 适用场景 1.5 使用语句 1.5.1 查看索引 1.5.2 创建索引 1.5.3 删除索引 2. 事务 2.1 概念 2.2 为什么使用事务 2.3 四大属性 2.3.1 原子性 2.3.2 一致性 2.3.3 持久性 2.3.4 隔离性 2.4 使用方法 1. 索引 1.1 概念 索引是为了加速对表中数据行的检索而创建的一种分散

  • mysql事务和隔离级别底层原理浅析

    目录 前言 一.事务底层原理浅析 原子性: 持久性 隔离性: 一致性: 二.隔离级别底层原理浅析 三.总结 前言 首先回顾一下什么是事务,事务是数据库操作的最小工作单元,是作为单个逻辑工作单元执行的一系列操作:这些操作作为一个整体一起向系统提交,要么都执行.要么都不执行:事务是一组不可再分割的操作集合(工作逻辑单元). 事务的特性: 原子性(Atomicity):原子性是指事务包含的所有操作要么全部成功,要么全部失败回滚.一致性(Consistency):事务执行的结果必须是使数据库从一个一致性

  • mysql 事务解析

    事务(transaction) 事务是业务逻辑的一个基本的单元组成. 每一个事务由一条条sql语句组成. 和事务相关的语句(insert,delete,update)这些DML语句 事务的存在保证了数据的安全性. 事务机制: 每一次执行DML语句都会记录操作,但不会修改数据,等到所有DML执行, 最后提交事务(删除记录,修改硬盘数据)或者回滚事务(删除记录,不修改数据). 事务由四大特性:ACID A:原子性,事务是最小的工作单元 C:一致性,事务中的DML语句要么都执行成功,要么都失败 I:隔

  • mysql事务详细介绍

    目录 简介 事务四个特性 事务隔离级别 验证 MVCC 当前读 快照读 当前读.快照读.MVCC关系 mvcc 解决的问题 MVCC实现原理 可见性规则 简介 事务是由一组sql语句组成的逻辑处理单元 事务四个特性 原子性(Atomicity): 要么都成功要么都失败 undo log实现 一致性(Consistent): 如转账前后两个数额总合保持不变 隔离性(lsolation):数据库提供一定的隔离机制,保证事务在不受外部并发操作影响的"独立"环境下运行 锁,mvcc多版本并发控

  • MySql索引详细介绍及正确使用方法

    MySql索引详细介绍及正确使用方法 1.前言: 索引对查询的速度有着至关重要的影响,理解索引也是进行数据库性能调优的起点. 索引是存储引擎用于快速查找记录的一种数据结构,通过合理的使用数据库索引可以大大提高系统的访问性能,接下来主要介绍在MySql数据库中索引类型,以及如何创建出更加合理且高效的索引技巧. 注:这里主要针对的是InnoDB存储引擎的B+Tree索引数据结构 2.索引的优点 1.大大减轻了服务器需要扫描的数据量,从而提高了数据的检索速度 2.帮助服务器避免排序和临时表 3.可以将

  • MySQL游标详细介绍

    目录 1.什么是游标(或光标) 2.如何使用游标 1.声明游标 2.打开游标 3.使用游标 4.关闭游标 3.代码举例 4.小结 1.什么是游标(或光标) 虽然我们也可以通过筛选条件 WHERE 和 HAVING,或者是限定返回记录的关键字 LIMIT 返回一条记录,但是,却无法在结果集中像指针一样,向前定位一条记录.向后定位一条记录,或者是随意定位到某一条记录,并对记录的数据进行处理. 这个时候,就可以用到游标.游标,提供了一种灵活的操作方式,让我们能够对结果集中的每一条记录进行定位,并对指向

  • Go GORM 事务详细介绍

    目录 禁用默认事务 事务 嵌套事务 手动事务 一个特殊的示例 SavePoint.RollbackTo 禁用默认事务 为了确保数据一致性,GORM 会在事务里执行写入操作(创建.更新.删除).如果没有这方面的要求,您可以在初始化时禁用它,这将获得大约 30%+ 性能提升. // 全局禁用 db, err := gorm.Open(sqlite.Open("gorm.db"), &gorm.Config{ SkipDefaultTransaction: true, }) // 持

  • MySql事务原理介绍及特性

    目录 1. 什么是事务 2. 事务是如何做到同时成功失败 3. 如何提交回滚事务 1. mysql 中默认的事务行为是怎样的 2. 回滚事务 3. 提交事务 4. 事务的4个特性 5. 事务的隔离性 1. 什么是事务 一个事务就是一个完整的业务逻辑. 什么是一个完整的业务逻辑? 假设转账,从A账户向B账户中转账10000. 将A账户的钱减去10000 ( update语句) 将B账户的钱加上10000 ( update语句) 这就是一个完整的业务逻辑. 以_上的操作是-一个最小的工作单元,要么同

  • Mysql索引详细介绍

    Mysql索引概述 所有MySQL列类型可以被索引.对相关列使用索引是提高SELECT操作性能的最佳途径.根据存储引擎定义每个表的最大索引数和最大索引长度.所有存储引擎支持每个表至少16个索引,总索引长度至少为256字节.大多数存储引擎有更高的限制. 在MySQL 5.1中,对于MyISAM和InnoDB表,前缀可以达到1000字节长.请注意前缀的限制应以字节为单位进行测量,而CREATE TABLE语句中的前缀长度解释为字符数.当为使用多字节字符集的列指定前缀长度时一定要加以考虑. 还可以创建

  • Java 基础之事务详细介绍

    java 事务详解 一.什么是事务 事务是访问数据库的一个操作序列,数据库应用系统通过事务集来完成对数据库的存取.事务的正确执行使得数据库从一种状态转换成另一种状态. 事务必须服从ISO/IEC所制定的ACID原则.ACID是原子性(atomicity).一致性(consistency).隔离性(isolation)和持久性(durability)的缩写事务必须服从ISO/IEC所制定的ACID原则.ACID是原子性(atomicity).一致性(consistency).隔离性(isolati

  • Mysql Explain 详细介绍

    Mysql Explain 这里做一个资料的全面整理. 一.语法 explain < table_name > 例如: explain select * from t3 where id=3952602; 二.explain输出解释 +----+-------------+-------+-------+-------------------+---------+---------+-------+------+-------+ | id | select_type | table | typ

  • python中使用mysql数据库详细介绍

    一.安装mysql 如果是windows 用户,mysql 的安装非常简单,直接下载安装文件,双击安装文件一步一步进行操作即可. Linux 下的安装可能会更加简单,除了下载安装包进行安装外,一般的linux 仓库中都会有mysql ,我们只需要通过一个命令就可以下载安装: Ubuntu\deepin 复制代码 代码如下: >>sudo apt-get install mysql-server >>Sudo apt-get install  mysql-client centOS/

  • Java连接MySql的详细介绍

    1. 现在工程(不是Src)上右键--Build Path--Add External Archives,选择驱动下的那个jar包,这是release版本,bin目录下的是debug版本. 示例在docs下的connector-j.html,里面有例子(其中的test是数据库名,换位自己的). 复制代码 代码如下: import java.sql.Connection; import java.sql.DriverManager; import java.sql.SQLException; Co

随机推荐