mysql mmvc_深入了解事务的原理

42c0f96b04cdacccac65ee14fef7b584.png

首页 专栏 java 文章详情

0

深入了解事务的原理

9d2d564462b7558f9433bc769da841ba.png

rookie_only 发布于 1 月 21 日

1、事务基础概念

1.1、什么是事务

引用百度百科上的一段话:

事务(Transaction),一般是指要做的或所做的事情。在计算机术语中是指访问并可能更新数据库中各种数据项的一个程序执行单元(Unit)。事务通常由高级数据库操纵语言或编程语言(如 SQL,C++ 或 Java)书写的用户程序的执行所引起,并用形如 begin transaction 和 end transaction 语句(或函数调用)来界定。事务由事务开始(begin transaction)和事务结束(end transaction)之间执行的全体操作组成。

通俗的来讲,就是我们要做一件事,但是这件事分成几个步骤,要么这件事做完,要么这件事不做才算,只有开始和结束两个状态,没有中间状态。

1.2、事务的四个特性(ACID)

原子性(atomicity)。一个事务是一个不可分割的工作单位,事务中包括的操作要么都做,要么都不做。

一致性(consistency)。事务必须是使数据库从一个一致性状态变到另一个一致性状态。一致性与原子性是密切相关的。

隔离性(isolation)。一个事务的执行不能被其他事务干扰。即一个事务内部的操作及使用的数据对并发的其他事务是隔离的,并发执行的各个事务之间不能互相干扰。(你插入数据不能影响我查询数据,在我事务还没结束的时候必须保证我事务开始和结束的数据是一样的,也就是一致性。)

持久性(durability)。持久性也称永久性(permanence),指一个事务一旦提交,它对数据库中数据的改变就应该是永久性的。接下来的其他操作或故障不应该对其有任何影响。

1.3、事务并发产生的问题

更新丢失:两个事务同时修改同一条数据,然后后面一个事务提交覆盖了前面一个事务的提交,如果第一个事务在事务还没结束时再次查询就会发现自己的更新丢失了。

借用一个例子:

设想银行发生丢失更新现象,例如一个用户账号中有10 000元人民币,他用两个网上银行的客户端分别进行转账操作。第一次转账9000人民币,因为网络和数据的关系,这时需要等待。但是这时用户操作另一个网上银行客户端,转账1元,如果最终两笔操作都成功了,用户的账号余款是9999人民币,第一次转的9000人民币并没有得到更新,但是在转账的另一个账号却会收到这9000元,这导致的结果就是钱变多,而账不平。

脏读:脏读读的是未提交数据。A 事务可以读取到 B 事务中未提交的数据。

不可重复读:不可重复读读取到的是已提交数据。不可重复读在一个事务中对某个集合的数据进行多次读取,然后另外一个事务同时对这个数据集合进行删除和修改操作,导致当前事务多次读取的数据是不一致的。

幻读:事务 A 按照一定条件进行数据读取, 期间事务 B 插入了相同搜索条件的新数据,事务 A 再次按照原先条件进行读取时,发现了事务 B 新插入的数据。

PS:简单来说,事务的执行不能脱离事务的四个特性。

1.4、事务的隔离级别 读未提交(READ UNCOMMITTED):顾名思义,就是一个事务可以读取另一个未提交事务的数据。 读已提交 (READ COMMITTED):就是一个事务读取到其他事务提交后的数据。解决了脏读问题。 可重复读(REPEATABLE READ):就是一个事务对同一份数据读取到的相同,不在乎其他事务对数据的修改。解决了脏读、不可重复读问题(MySQL中幻读使用Next-Key Lock算法解决了)。 序列化读(串行读)(SERIALIZABLE):事务串行化执行,隔离级别最高,牺牲了系统的并发性。解决了脏读、幻读、不可重复读问题。

1.5、MySQL 事务

以下内容都是 InnoDB 数据库引擎的相关概念。

1.5.1、MySQL 零散概念

1.5.1.1、MySQL 锁概念

行级锁:共享锁(S锁)和排它锁(X锁)

两种锁的兼容性:

X S

X 不兼容 不兼容

S 不兼容 兼容

X锁和任意锁都不兼容

意向共享锁(IS):事务想要获取表中某几行的共享锁

意向排它锁(IX):事务想要获取表中某几行的排它锁

兼容性:

IS IX S X

IS 兼容 兼容 兼容 不兼容

IX 兼容 兼容 不兼容 不兼容

S 兼容 不兼容 兼容 不兼容

X 不兼容 不兼容 不兼容 不兼容

可以发现意向锁之间相互兼容,而 X 锁还是与任意锁都不兼容,意向排它锁和 S 锁不兼容(想要对细粒度上锁必须先将粗粒度上锁)。

快照读:简单的 select 操作,没有 lock in share mode 或 for update ,快照读不会加任何的锁,而且由于 MySQL 的一致性非锁定读的机制存在,任何快照读也不会被阻塞。

当前读:读取的是记录数据的最新版本,并且当前读返回的记录都会加上锁,保证其他事务不会再并发的修改这条记录。也就是 insert ,update ,delete ,select..in share mode 和 select..for update ,当前读会在所有扫描到的索引记录上加锁,不管它后面的 where 条件到底有没有命中对应的行记录。

一致性的非锁定读:是指 InnoDB 通过多版本控制的方式来读取当前执行时间数据库中行的数据。如果读取的行正在进行 delete 或者 update 操作,这是读取操作不会因此会等待锁的释放,相反的,InnoDB 会去读取行的一个快照数据。

多版本并发控制(MMVC):快照数据是当前行数据的一个历史版本,每行记录可能有多个版本。一个行记录可能不止一个快照数据,一般称这种技术为行多版本技术,由此带来的并发控制,也称之为多版本并发控制。

对于读已提交和可重复读的隔离级别中,InnoDB默认使用都是一致性的非锁定读,但是对于快照的定义却不相同。在读已提交中,一致性的非锁定读总是读取最新的快照数据。而对于可重复读来说,读的总是事务开始时的行数据版本。

行锁的三种算法: Record Lock(单个行记录上的锁):单条索引记录上加锁,Record Lock 锁住的永远是索引,而非记录本身,即使该表上没有任何索引,那么 InnoDB 会在后台创建一个隐藏的聚集主键索引,那么锁住的就是这个隐藏的聚集主键索引。所以说当一条sql没有走任何索引时,那么将会在每一条聚集索引后面加 X 锁,这个类似于表锁,但原理上和表锁应该是完全不同的。 Gap Lock(间隙锁,锁定一个范围,但不包括记录本身):在索引记录之间的间隙中加锁,或者是在某一条索引记录之前或者之后加锁,并不包括该索引记录本身。 Next-Key Lock( Record Lock + Gap Lock ,锁定一个范围,包括记录本身):Next-Key Lock 是结合了 Gap Lock 和Record Lock 的一种锁定算法,在 Next-KeyLock 算法下,InnoDB 对于行的查询都是采用这种锁定算法。例如一个索引有10,11,13 和 20 这四个值,那么该索引可能被 Next-Key Locking 的区间为:(-∞,10]、[10,11]、[11,13]、[13,20]、[20,+∞)

锁升级:锁升级(Lock Escalation)是指将当前锁的粒度降低。举例来说,数据库可以把一个表的1000个行锁升级为一个页锁,或者将页锁升级为表锁。如果在数据库的设计中认为锁是-种稀有资源,而且想避免锁的开销,那数据库中会频繁出现锁升级现象。

1.5.1.2、如何手动加锁

— mysql 加共享锁

select … lock in share mode;

— mysql 加排它锁

select … for update;

1.5.1.3、脏页与脏数据

脏页指的是在缓冲池中已经被修改的页,但是还没有刷新到磁盘中,即数据库实例内存中的页和磁盘中的页的数据是不一致的,当然在刷新到磁盘之前,日志都已经被写人到了重做日志文件中。

而所谓脏数据是指事务对缓冲池中行记录的修改,并且还没有被提交(commit)。脏读读的就是脏数据。

1.5.1.4、redo 与 undo

redo:

redo 也叫做重做日志,它用来实现事务的持久性,其由

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值