栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > Java

mysql中的事务

Java 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

mysql中的事务

前言

这是本人从网上文章、B站等各处参考总结所得出,有不足、不对的 恳请指出

什么是事务

比如说有个场景,我们需要插入多条相关联的数据到数据库,这个过程可能会遇到下面这些问题:

1:数据库中途突然因为某些原因挂掉了。
2:因为网络原因连接不上数据库了。

上面的问题都可能会导致数据的不一致性(部分成功)。为了保证数据的一致性,系统必须能够处理这些问题。事务就是抽象出来的一种机制。事务的概念起源于数据库。

总而言之:事务是逻辑上的一组操作,要么都执行,要么都不执行。

事务的简单使用


1:start transaction; //开启事务

2:update ex_drug set number=number-10 where id=‘15’; (数据在内存,未写入磁盘) //执行sql

3:(ROLLBACK;) (基于undo log实现) //回滚

4:commit;(写入磁盘) //提交事务

事务的四大特性


原子性(atomicity):
一个事务就是一个最小单位,整个事务中的所有操作要么全部提交成功,要么全部失败回滚。基于undo log日志实现

一致性(consistency):
执行事务前后,数据保持一致, 例如转账业务中,无论事务是否成功,转账者和收款人的总额应该是不变的;(质量守恒定律)
可以理解为事务的目的,而原子性、隔离性、持久性均是为了保障这个目的的手段

隔离性(isolation):
多个用户并发访问数据时,各个事务相互隔离,互不干扰。数据库提供四种隔离级别
Read UnCommitted(读未提交)
Read Committed(读已提交)
Repeatable Read(可重复读)
Serializable(串行)

持久性(durability)
一个事务被提交之后。它对数据库中数据的改变是持久的,即使数据库发生故障也不应该对其有影响。
(redo log日志保证的,下面介绍下三大日志)

mysql三大日志

binlog(mysql 执行器里)
日志中包含了一系列变更的操作,例如变更表结构、增、删、改数据等,不包括查询数据。
binlog有三种格式
1:statement:记录的是修改SQL语句,会存在主从不一致的情况,比如说执行uuid() 函数随机生成,主、从得到的结果就不一致 (读已提交下有问题,因此mylsql默认隔离级别为可重复读)
2:row(5.1.5开始):记录的是每行实际数据的变更,缺点是日志量大
3:mixed(5.1.8开始):statement和row模式的混合,系统会自动判断 该 用 Statement 还是 Row:一般的语句修改使用 Statement 格式保存 binlog;对于一些 Statement 无法准确完成主从复制的操作,则采用 Row 格式保存 binlog

redo log(innodb里)

redo log主要是为了保证事务持久性(事务提交后各种不可抗拒因素导致的数据丢失),是通过redo log恢复的,redo log记录的是在某个数据页上做了某个修改,所以 redo 日志整体来说是比较小的,存储的信息不多,redo log则是在事务进行中不断地被写入,是循环写,redo log 只会记录未刷入盘的日志,已经刷入磁盘的数据都会从 redo log 日志文件里删除

redo log包括两部分:一个是内存中的日志缓冲(redo log buffer),另一个是磁盘上的日志文件(redo log file)。
redo log有prepare和commit两个状态,是个二阶段提交过程,是一种保护机制(保证持久性,后面有图解)
redo log是InnoDB特有的,且日志上的记录落盘后会被覆盖掉,也就不能用于数据恢复

undo log(innodb里)
主要记录了数据的逻辑变化
原子性由undo log日志(回滚)来保证,因为undo log记载着数据修改前的信息,比如我们要
insert 一条数据了,那undo log 会记录的一条对应的 delete 日志。
update 一条记录时,那undo log会记录之前的旧值的update记录
(保证原子性)

redo log二阶段提交

事务问题

1:脏读(Drity Read):
某个事务已更新一份数据,另一个事务在此时读取了同一份数据,这个时候如果前一个事务RollBack了操作,则后一个事务所读取的数据就会是不正确的。(脏读主要是针对的是事务回滚操作)
(A事务进行转账,B事务看到数据满足要求,就进行了发货,A回滚了 就炸了)

2:重复读(Non-repeatable read):
在一个事务的两次查询之中数据不一致,这可能是两次查询过程中间插入了一个事务更新了原有的数据。不可重复读主要针对的是修改(update)

3:幻读(Phantom Read):
在一个事务的两次查询中数据笔数不一致,例如有一个事务范围查询了几列数据,而另一个事务却在此时插入(删除)了新的几列数据,先前的事务在接下来的查询中,就会发现有几列数据是它先前所没有的。幻读主要是针对新增(insert)和删除(delect);
(即使我们把所有的的记录都加上锁,还是阻止不了新插入的记录,innodb引入了间隙锁来解决这个问题,然后更新的数据会加上行锁,行锁加间隙锁的组合也被称为临键锁(Next-Key Lock))

事务的隔离级别

1:Read UnCommitted(读未提交)
是事务中最低的级别,该级别下的事务可以读取到另一个事务中未提交的数据,脏读、重复读、幻读都无法避免。
由于该级别较低,在实际开发中避免不了任何情况,所以一般很少使用。

2:Read Committed(读已提交)
大多数的数据库管理系统的默认隔离级别都是Read Committed(读已提交),该级别下的事务只能读取其他事务中已经提交的内容,可以避免脏读,但是不能避免重复读和幻读的情况。

互联网项目基本都是将隔离级别设为读已提交
缺点处理:
业务不关心数据是不是“某一个时间点的快照”,如果需要 可以加锁,可以手动使用 select … lock for share 或者 select … for update 手动加锁

优点:
在可重复读隔离级别下,条件列未命中索引会锁表!而在已提交读隔离级别下,只锁行;不可重复读问题在开发中是可以接受的,毕竟你数据都已经提交了,读出来本身就没有太大问题

3:Repeatable Read(可重复读)
对同一字段的多次读取结果都是一致的,除非数据是被本身事务自己所修改,可以阻止脏读和不可重复读,但没有彻底解决幻读,是MySQL默认的事务隔离级别
①:这里的没有彻底解决幻读,是指当前读存在幻读问题,SQL标准下会引入mvcc,所以读是快照读,不会有幻读问题
②:对于更新操作中存在的当前读问题,innodb通过引入间隙锁来解决了
③:为什么是myslq默认的隔离级别?
历史原因:binlog当初只支持statement格式,记录的是修改SQL的语句,读已提交隔离级别下会存在主从数据不一致问题(下面有举例),可重复读引入间隙锁,不会有这种问题。

4:Serializable(串行)
事务的最高隔离级别,它会强制对事务进行排序,使它们彼此之间不会发生冲突,从而解决脏读、幻读、重复读的问题。实际上,就是事务在读、写操作时,会加表级的读锁和写锁,直到事务结束才释放。这个级别,可能导致大量超时现象和锁竞争,实际应用中很少使用(分布式事务会使用,道听途说)。

读已提交隔离级别下会存在主从数据不一致问题

转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/1023653.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号