zoukankan      html  css  js  c++  java
  • 【MySql学习笔记】MySql事务

    一、什么是事务

        逻辑上的一组操作,要么都执行,要么都不执行。经典例子:转账问题,需要保证转出和转入同时成功或者同时失败才行。

        事务又有数据库事务和分布式事务。如果项目中是单体架构,那么就是数据库事务。数据库事务可以保证一系列的数据库操作可以同时成功或者同时失败

    二、事务的四大特性

    原子性

        事务是最小的工作单元,不能再进行分割,作为一个整体被执行,要么全部成功,要么全部失败。

        如何保证原子性?由undo log来保证,记录了需要回滚日志的信息,事务回滚的时候就撤销已经执行成功的Sql语句。

    一致性

        事务执行以后,数据是保持一致的。秒杀项目中,减少的库存和增加的销量要保证相同。

        如何保证一致性?其他三种特性保证就可以保证一致性。

    隔离性

        多个事务并发的时候,一个事务的执行不会影响到其他事务的执行。

        如何保证隔离性?锁机制,MVCC。

           MVCC:多版本并发控制,读取数据的时候通过类似快照的形式将数据保存,这样一来读锁和写锁就不冲突了,不同事务的session会看到自己特定版本的数据,版本链。好处:提高并发的读写能力,不需要加锁,通过多个修改的历史版本就可以让多个事务并发的读写。

        MVCC核心实现(版本链+ReadView表的隐藏列:记录事务的id(trx_id)以及上一个版本数据的地址(roll_pointer,回滚指针);undo log:记录数据各个版本的修改历史,即事务链;Read View:读视图,用于判断哪一个版本对事务是可见的。MVCC保证并发(两种隔离级别下):在读已提交的时候,每次查询都会生成新的Read View;在不可重复读的时候,每次查询不会生成新的Read View,一直使用事务开始时生成的Read View

        事务的起点:不是begin/transaction命令,而是在执行这个命令之后,第一个操作的InnoDB表的语句,事务才会真正的启动,然后才会申请事务idMySql内部是严格按照事务的启动顺序来分配事务的id的。

    持久性

        事务一旦提交,对数据库的修改应该永久的保存。

        如何保证持久性?内存 + redo log。MySql在记录数据的时候在内存中和redo log中都记录了这次操作,如果出现宕机的情况就可以从redo log中对数据进行恢复。

        redo log写的过程?(去看两阶段提交)首先InnoDB事务进入prepare状态,prepare阶段redo log记录事务的id和内容,prepare成功以后进入commit阶段,首先是binlog写盘,继续将事务日志持久化到binlog之中,binlog记录事务id和内容,持久化成功,InnoDB事务进入commit状态,redo log里面会写入一个commit记录。最后在系统空闲的时候redo log刷盘。

    • 为什么MySql会突然变慢一下?

      • 内存数据页和磁盘数据页不一致的时候,这个内存页就是"脏页"。内存数据写入磁盘以后,内存和磁盘上面的数据一致了,此时内存就是"干净页"。

      • 在更新数据库的时候先写日志,当空闲的时候才会将数据更新到磁盘,但是当redo log写满了,要flush"脏页",也就是把内存中的数据写入磁盘中,此时就会导致MySql执行慢一下。

      • 数据库每次往磁盘中写数据的时候,不是直接写入磁盘的,操作系统底层分为两个部分:用户空间和内核空间,内核空间接管了所有的硬件状态,写入的时候数据先写入内存,通过系统调用将数据在写入磁盘。

    三、多事务并发操作数据库引发的问题

    3-1 开启事务 

     图3-2 事务回滚

     图3-3 事务提交

     3-4 设置隔离级别

     图3-5 关闭自动提交

        丢失更新:两个不同的事务同时修改相同的数据,然后在各自的事务中同时修改了这个数据,那么先提交的事务修改的数据会被后提交的事务修改的数据覆盖掉,这样先提交的事务更新的数据就会丢失。(CAS操作 -> ABA问题 -> CAS+版本号)

        脏读:事务A在修改数据,但是还没有进行提交,此时另外一个事务去读取了事务A修改过的数据,这种情况就属于脏读。因为事务A还没有提交,可能后面因为异常或者其他原因造成数据回滚的话,那么这个无效修改的数据已经被另外一个事务读取并且使用了的话,另外一个事务就读取到了脏数据。

     图3-6 脏读

        不可重复读:首先事务A先读取了一个数据并没有提交事务,然后事务B对这条数据进行修改并且提交,然后事务A再次读取这个数据发现数据与之前读取的不一致。

      图3-7 不可重复读

     3-8 不可重复读

        幻读:事务A读取数据的时候出现了n条数据,事务B在事务A执行的过程中增加了一条数据,事务A再次读取的时候就变成了n+1条数据。

    四、事务的隔离级别

        读未提交(Read Uncommitted:允许脏读取,如果一个事务已经开始写数据,那么就不允许别的事务在写了,但是可以允许比的事务读取这行数据。

     4-1 读未提交时出现脏读

     4-2 读未提交是出现不可重复读

        读已提交(Read committed:允许不可重复读,不允许脏读。读取数据的事务允许其他事务继续访问这行数据,但是没有提交的写事务不允许其他事务访问这行数据。

     4-3 读已提交时不会出现脏读

     4-4 读已提交时出现不可重复读

        可重复读(Repartable Reads:不允许不可重复读和脏读。读取数据的事务不允许写事务访问这行数据,写事务不允许其他事务访问这行数据。

     图4-5 可重复读时不会出现脏读和不可重复读

        序列化(Serializable:严格的事务隔离,事务只能序列化执行,不能并发执行。

     4-6 序列化时事务不能并发执行

          MySql默认隔离级别是可重复读,事务隔离级别越高,数据的完整性和一致性就越好,但是对于并发操作的影响也就越大。

     图4-7 数据库默认隔离级别

  • 相关阅读:
    Android仿qq聊天记录长按删除功能效果
    charles工具抓包教程(http跟https)
    瀑布流StaggeredGridView 下拉刷新
    Android微信分享图片大于32k进行压缩
    Android使用TextureView播放视频
    ViewPager+RadioGroup实现标题栏切换,Fragment切换
    android:theme决定AlertDialog的背景颜色
    实现本地音乐选择,播放,带可拖动进度条
    android图片透明度跟缩放大小动画事件
    Android中实现双击事件
  • 原文地址:https://www.cnblogs.com/zut-syp/p/15313125.html
Copyright © 2011-2022 走看看