~ 如有错误 恳请指正
1.什么是事务?事务特点以及开启与提交演示
把需要保证原子性、隔离性、一致性和持久性的一个或多个数据库操作称之为一个事务
-
事务的特点-- 原子性 Atomicity -- 要么都成功 要么都失败 -- 隔离性 Isolation -- A事务在修改某条记录时候(也可以理解为状态转换,如扣钱,加钱等) 不会影响B事务内的状态转换(如扣钱,加钱) -- 一致性 Consistency -- 只要最后的结果符合所有现实世界中的约束,那么就是符合一致性的。 -- 一致性由原子性和隔离性保证 -- 持久性 Durability -- 当现实世界的一个状态转换完成后,这个转换的结果将永久的保留,这个规则被称为持久性 -
事务开启,提交,关闭以及事务的类型,隐示提交和保存点-- 开启 BEGIN;-- 开启事务 START TRANSACTION;-- 开启事务 注意 他可以携带事务类型 -- 类型 -- READ ONLY:标识当前事务是一个只读事务,也就是属于该事务的数据库操作只能读取数据,而不能修改数据 -- READ WRITE:标识当前事务是一个读写事务,也就是属于该事务的数据库操作既可以读取数据,也可以修改数据。 -- WITH CONSISTENT SNAPSHOT:启动一致性读 -- eg: (一般我们不设置两种事务类型哦) START TRANSACTION READ ONLY; START TRANSACTION READ ONLY, WITH CONSISTENT SNAPSHOT; START TRANSACTION READ WRITE, WITH CONSISTENT SNAPSHOT -- 如果不指定 那么默认是读写模式 -- 提交与终止 COMMIT; -- 提交事务: 一般程序中我们不需要手动提交 ROLLBACK; -- 终止事务: 一般程序中我们不需要手动提交 -- 查看数据库是否为自动提交 SHOW VARIABLES LIKE 'autocommit'; -- 查看事务自动提交属性是否开启 Variable_name Value autocommit ON -- *** 注意 *** 平时我们不设置事务的话 那么每一条语句都算是一个独立的事务,这种特性称之为事务的自动提交 so 知道我们为啥在 service层设置 @Transactional(rollbackFor = Exception.class)了吧 -- 事务的隐示提交与保存点 -- 隐示提交 DDL语句 && ALTER 、CREATE 、DROP 、GRANT、RENAME 、REVOKE、SET PASSWORD等语句时也会隐式的提交前边语句所属于的事务。 -- 保存点 SAVEPOINT 保存点名称; -- 回滚到某保存点 ROLLBACK TO 保存点名称;
事务回滚示例:
事务正常提交示例:
事务保存点演示:
插入前:
插入两条在1后设置保存点2完成后回滚到保存点1:
2.并发情况下事务会产生的问题&&隔离级别
2.0 脏写 有的地方也叫丢失更新 这种情况很严重 也就是说 某事务修改了另一个未提交事务修改过的数据,这还了的???所以4种隔离级别种 最低的隔离级别 读未提交 都会解决掉脏写这种问题
2.1 脏读:
如果一个事务读到了另一个事务未提交过的数据,那就意味着发生了脏读
脏读示意图:
2.2 可重复读
举例: 事务 1 读取表的一条数据期间,事务 2 更新了该条记录并提交,事务 1 再次读取该表该条记录时,发现和第一次内容不一致。也就是说某事务在执行过程中多次读取到某条记录的结果不一样。 示意图如下:
2.3 幻读
如果一个事务先根据某些条件查询出一些记录,之后另一个事务又向表中插入了符合这些条件的记录,原先的事务再次按照该条件查询时,能把另一个事务插入的记录也读出来,那就意味着发生了幻读
示意图:
区别: 可重复度和幻读的区别:
幻读一般是针对insert可重复度一般是update
幻读和不可重复读都是读取了另一条已经提交的事务;但不可重复读查询的都是同一个数据项,而幻读针对的是一批数据整体(比如数据的个数)。
事务隔离级别 4种 mysql默认是不可重复读 oracle默认 读已提交
-
读未提交 (Read Uncommitted) 是指: 一个事务还没提交时,它做的变更就能被别的事务看到。
可以解决 脏写 但是 脏读,可重复读 幻读这3个问题解决不了 -
读已提交 (Read Committed) 是指: 一个事务提交之后,它做的变更才会被其他事务看到。
可以解决 脏读(因为其规定了 只有在已提交后 才会被其他事务看到) ,但是重复读和幻读问题解决不了 -
可重复读 (Repeatable Read) 是指: 一个事务a执行过程中看到的数据,总是跟这个a事务在启动时看到的数据是一致的(本质是a事务对要读取的数据 比如表 b_table 加了写锁(行锁) 从而保证了多次读取b_table时的数据一致性)。
可以解决 脏读,可重复读 但是不能解决幻读 -
串行化 (Serializable): 顾名思义是对于同一行记录,“写”会加“写锁”,“读”会加“读锁”。当出现读写锁冲突的时候,后访问的事务必须等前一个事务执行完成,才能继续执行。
可以解决 脏读,可重复读,幻读
3. binlog
binlog是个啥?
- binlog是用于记录数据库执行的写入性操作(不包括查询)信息,以二进制的形式保存在磁盘中。
- binlog是mysql的逻辑日志,并且由Server层进行记录,使用任何存储引擎的mysql数据库都会记录binlog日志。
- binlog 类型: - 逻辑日志: 可以简单理解为记录的就是sql语句。 - 物理日志: mysql数据最终是保存在数据页中的,物理日志记录的就是数据页变更 。
注意: binlog是通过追加的方式进行写入的,可以通过 max_binlog_size 参数设置每个 binlog
文件的大小,当文件大小达到给定值之后,会生成新的文件来保存日志。
binlog使用场景
在实际应用中, binlog 的主要使用场景有两个,分别是 主从复制 和 数据恢复 。
- 主从复制 :在
Master端开启binlog,然后将binlog发送到各个Slave端,Slave端重放binlog从而达到主从数据一致。 - 数据恢复 :通过使用
mysqlbinlog工具来恢复数据。
binlog刷盘时机
对于 InnoDB 存储引擎而言,只有在事务提交时才会记录 biglog ,此时记录还在内存中,那么 biglog
是什么时候刷到磁盘中的呢? mysql 通过 sync_binlog 参数控制 biglog 的刷盘时机,取值范围是 0-N
- 0:不去强制要求,由系统自行判断何时写入磁盘;
- 1:每次
commit的时候都要将binlog写入磁盘; - N:每N个事务,才会将
binlog写入磁盘。
从上面可以看出, sync_binlog 最安全的是设置是 1 ,这也是 MySQL 5.7.7
之后版本的默认值。但是设置一个大一些的值可以提升数据库性能,因此实际情况下也可以将值适当调大,牺牲一定的一致性来获取更好的性能。
4. undo log
undo log是个啥?
原子性 底层就是通过undo log实现的。undo log主要记录了数据的逻辑变化,比如一条INSERT语句,对应一条DELETE的undo log,对于每个UPDATE语句,对应一条相反的UPDATE的undo log,这样在发生错误时,就能回滚到事务之前的数据状态。同时,undo log也是MVCC(多版本并发控制)实现的关键。
5. redo log 重做日志
redo log是什么?
redolog是一种基于磁盘的数据结构,用于在崩溃恢复期间纠正失败事务写入的数据。 在正常操作期间, redolog对由 SQL 语句或低级 API 调用产生的更改表数据的请求进行编码。redo log 保证持久化的重要特性: ->>>>>(在初始化期间和接受连接之前,会自动重放在意外关闭之前未完成更新数据文件的修改 ) <<<<<<。
注意 : redo log是InnoDB引擎特有的为什么会有 redo log?
因为如果每一个事务提交后都写入到磁盘的话 mysql的压力可想而知是多么的大 (不光要写业务过来的insert uodate delete 还得写日志数据) so mysql设计出redolog 用于减轻mysql io压力redo log组成
1.redolog buffer
2.redologfileredo log参数说明
redo log和undo log是如何写入磁盘的 看图说话
先写缓存 再写磁盘 也被简写为 WAL(Write-Ahead Logging) 即每一条DML都会先写入缓存 然后再由fsync()函数写入磁盘 ps:很多地方都用到了该技术 如 mysql的buffer pool 的(flush链表) nio中使用的 mmap filechannel等 我个人理解这些东西的共性就是离不开两个字 --- 刷盘
binlog和redolog区别
现有一问: insert update delete 操作 在mysql内部是怎么个执行过程???成功会怎样?失败会怎样?
- 解: 看图
6. mysql 锁
- 在我的另外一篇文章中~ 因为这里放不下了 > juejin.cn/post/699774…
7. mvcc多版本并发控制
东说起来东西太多了以后在做深入分析, 这里只说MVCC与事务隔离级别的关系
Read View用于支持RC(Read Committed,读提交)和RR(Repeatable Read,可重复读)隔离级别的实现。
RR(可重复读)、RC(读已提交)生成时机
RC隔离级别下,是每个快照读都会生成并获取最新的Read View;保证是最新提交的数据- 而在
RR隔离级别下,则是同一个事务中的第一个快照读才会创建Read View,之后的快照读获取的都是同一个Read View,之后的查询就不会重复生成了,所以一个事务的查询结果每次都是一样的。保证不重复读
解决幻读问题
快照读:通过MVCC来进行控制的,不用加锁。按照MVCC中规定的“语法”进行增删改查等操作,以避免幻读。当前读:通过next-key锁(行锁+gap锁)来解决问题的。
RC、RR级别下的InnoDB快照读区别
- 在RR级别下的某个事务的对某条记录的第一次快照读会创建一个快照及Read View, 将当前系统活跃的其他事务记录起来,此后在调用快照读的时候,还是使用的是同一个Read View,所以只要当前事务在其他事务提交更新之前使用过快照读,那么之后的快照读使用的都是同一个Read View,所以对之后的修改不可见;
- 即RR级别下,快照读生成Read View时,Read View会记录此时所有其他活动事务的快照,这些事务的修改对于当前事务都是不可见的。而早于Read View创建的事务所做的修改均是可见
- 而在RC级别下的,事务中,每次快照读都会新生成一个快照和Read View, 这就是我们在RC级别下的事务中可以看到别的事务提交的更新的原因
参考:
dev.mysql.com/doc/refman/…
juejin.cn/book/684473…
segmentfault.com/a/119000002…