MYSQL中的事务

一、事务

        事务,由一个有限的数据库操作序列构成,这些操作要么全部执行,要么全部不执行,是一个不可分割的工作单位。

二、事务的四大特征

1.原子性(Atomicity):事务作为一个整体被执行,包含在其中的对数据库的操作要么全部都执行,要么全部都不执行;

2.一致性(Consistency):指在事务开始之前和结束以后,数据不会被破坏。假如A账户给B账户转10块钱,不管成功与否,A和B的总金额是不变得;

3.隔离性(Isolation):多个事务并发访问得时候,事物之间是相互隔离得,一个事务不应该被其他事务干扰,多个并发事务之间要相互隔离;

4.持久性(Durability):表示事务完成提交后,该事务对数据库所作得操作更改,将持久得保存在数据库中。

三、事务并发存在的问题

1.脏读

        假设现在有两个事务A、B,事务A、B交替执行,事务A在执行查询操作,事务B在执行修改操作,此时事务A读到的是事务B未提交的数据,这就是脏读;

2.不可重复读

        假设依旧是有两个事务A、B,在事务A范围内进行两个相同的查询时,事务B在其中一次事务A查询后进行了修改操作并提交,导致事务A的两次查询同一条记录却返回不同结果,这就是不可重复读;

3.幻读

        依旧是事务A、B,事务A查询一个范围的结果集,另一个事务B往这个范围中插入/删除了数据,并静悄悄地提交,然后事务A再次查询相同地范围,两次读取得到地结果集不一样了,这就是幻读。

四、事务的隔离级别应对

  • 读未提交(read uncommitted):存在脏读问题,是隔离级别最低地一种;
  • 读已提交(read committed):存在不可重复读问题,隔离级别高于读未提交;
  • 可重复读(repeatable read):可能存在幻读问题,隔离级别高于读已提交;
  • 串行化(serializable):当数据库隔离级别设置未serializable时,事务B对表的写操作,在等事务A 的读操作。其实,这是隔离级别中最严格的,读写都不允许并发。它保证了最好的安全性,性能却是个问题;

五、MYSQL隔离级别实现原理

实现隔离机制的方法主要有两种:读写锁、一致性快照读,即MVCC

  • 读未提交:采取的是读不加锁原理

        事务读不加锁,不阻塞其他事务的读和写;事务写阻塞其他事务写,但不阻塞其他事务读;

  • 串行化:

        所有select语句会隐式转换未select...for share,即加共享锁;读共享锁,写加排他锁,读写互斥。如果有未提交的事务正在修改某些行,所有select这些行的语句都会阻塞

  • MVCC原理:MVCC(Mutil-Version Concurrency Control),中文叫多版本并发控制,它是通过读取历史版本的数据,来降低并发事务冲突,从而提高并发性能的一种机制。它的实现依赖于隐式字段、undo字段、快照读&当前读、Read View。    
    • 隐式字段:对于InnoDB存储引擎,每一行记录都有两个隐藏列DBTRXID、DBROLLPTR,如果表中没有主键和非NULL唯一键时,则还会有第三个隐藏的主键列DBROWID。
      • DBTRXID:记录每一行最近一次修改(修改/更新)它的事务ID,大小为6个字节;
      • DBROLLPTR:这个隐藏列就相当于一个指针,指向回滚段的undo日志,大小为7字节;
      • DBROWID:单调递增的行ID,大小为6字节;
    • undo日志:多个事务并行操作某一行数据时,不同事务对该行数据的修改会产生多个版本,然后通过回滚指针(DBROLLPTR)连一条Undo日志链;
      • 事务未提交的时候,修改数据的镜像(修改前的旧版本),存到undo日志里。以便事务回滚时,恢复旧版本数据,撤销未提交事务数据对数据库的影响;
      • undo日志是逻辑日志。可以这样认为,当delete一条记录时,undo log中会记录一条对应的insert日志,当update一条记录时,它记录一条对应相反的update记录;
      • 存储undo日志的地方,就是回滚段。
    • 快照读&当前读
      • 快照读:读取的是记录数据的可见版本(有旧的版本),不加锁,普通的select语句都是快照读;
      • 当前读:读取的是记录数据的最新版本,显示加锁的都是当前读;
    • Read View:事务执行快照时,产生的读视图
      • 事务执行快照读时,会生成数据库系统当前的一个快照,记录当前系统中还有哪些活跃的读写事务,把他们放到一个列表里;
      • Read View主要是用来做可见性判断的,即判断当前事务可见哪个版本的数据;
      • 可见性规则:
        • m_ids:当前系统中那些活跃的读写事务ID,它数据结构为一个List;
        • minlimitid:m_ids事务列表中,最小的事务ID;
        • maxlimitid:m_ids事务列表中,最大的事务ID;
          • 如果DBTRXID<minlimitid,表明生成该版本的事务在生成ReadView前已经提交(因为事务ID是递增的),所以该版本可以被当前事务访问;
          • 如果DBTRXID>maxlimitid,表明生成该版本的事务在生成ReadView后才生成,所以该版本不可以被当前事务访问;
          • 如果minlimitid<=DBTRXID<=maxlimitid,需要判断m_ids.contains(DBTRX_ID),如果在,则代表Read View生成时刻,这个事务还活跃,还没有commit,修改的数据,当前事务也是看不见的;如果不在,则说明这个事务在Read View生成之前就已经commit了,修改的结果,当前的事务是能看见的。

注意:RP和RC隔离级别最大的区别就是:RC每次读取数据前都生成一个ReadView,而RP只在第一次读取数据时生成一个Read View。     

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值