zoukankan      html  css  js  c++  java
  • MySQL——事务

    一、事务

    1、事务的四个特性ACID

    ① 原子性(atomicity):一个事务必须被视为一个不可分的最小工作单元,整个事务中所有操作要么全部提交成功,要么全部失败回滚。

    ② 一致性(consistency):数据库总是从一个一致性状态转化到另一个一致性状态。

    ③ 隔离性(isolation):一个事务所做的修改在最终提交前,对其他事务是不可见的。

    ④ 持久性(durability):一旦事务提交,所做的修改就会永久保存到数据库(磁盘)中,即使系统奔溃,也不会丢失。

    2、事务的隔离级别

    ① 未提交读(READ UNCOMMITTED):事务中的修改,即便没有提交,对其他事务也都是可见的。

    ② 提交读(READ COMMITTED):一个事务从开始直到提交前,所做的任何修改对其他事务是不可见的。这是大多数数据库系统默认的隔离级别,但MySQL不是。这个级别有时候也叫不可重复读(nonrepeatable read),因为两次执行同样的查询,可能会得到不一样的结果。

    ③ 可重复读(REPEATABLE READ):同一事务中多次读取同样的结果是一致的。(Mysql默认的事务隔离级别)

    ④ 可串行化(SERIALIZABLE):最高的隔离级别。强制事务串行执行。

    脏读:事务可以读取未提交的数据

    幻读:当事务A在读取某个范围的记录时,事务B又在该范围内插入了新的记录,事务A再次读取该范围的记录时,会产生幻行。

    3、死锁

    死锁的四个条件:资源互斥,请求并保持,不可剥夺,循环等待

    事务可能会导致死锁:两个或多个事务在同一资源上相互占用,并请求锁定对方占用的资源,从而导致恶性循环的现象。

    为了解决这种问题,数据库系统实现了各种死锁检测死锁超时机制。越复杂的系统,越能检测到死锁的循环依赖,并立即返回一个错误,比如InnoDB存储系统。

    还有一种解决方式,就是当查询的时间达到锁等待超时的设定后放弃锁请求,这种方式通常来说不太好。

    InnoDB目前处理死锁的方法是,将持有最少行级排它锁的事务进行回归。死锁的产生于存储引擎有关

    4、事务日志

    事务日志可以帮助提高事务的效率。

    使用事务日志,存储引擎在修改表的数据时只需要修改其内存拷贝,再把该修改行为记录持久化到硬盘的事务日志中,而不用每次都将修改的数据本身持久化到磁盘。

    事务日志采用的是追加的方式(跟kafka消息持久化一样),写日志的操作是磁盘上一小块区域内的顺序I/O,不是随机I/0,基本不需要多个地方移动磁头。

    事务日志持久化以后,内存中被修改的数据会由后台异步刷回磁盘,目前大多数存储引擎都是这样实现的,我们通常称之为预写式日志(Write-Ahead Logging),修改数据需要写两次磁盘。

    如果数据修改已经记录到事务日志并持久化,数据本身还没有写回磁盘,此时宕机了,存储引擎重启时会根据事务日志自动恢复这部分数据。

    二、MySQL中的事务

     MySQL提供了两种事务型的存储引擎:InnoDB和NDB Cluster。另外还有一些第三方引擎也支持事务。

    1、自动提交(AUTOCOMMIT)

    MySQL默认采用自动提交模式。也就是说,如果不是显示地开始一个事务,则每个查询都被当作一个事务执行提交操作。即进行update-query操作,update可视为事务开启,执行query时commit

    在当前连接中,可以通过设置AUTOCOMMIT变量来启用或者禁用自动提交模式  show variables like ‘autocommit’;

     当自动提交关闭(设置为OFF)时,,所有的查询都是在一个事务中,直到显示地执行COMMIT提交或者ROLLBACK回滚,该事务结束,同时又开始了另一个新事务,

    修改AUTOMMIT对非事务型的表,比如MyISAM或者内存表,不会有任何影响,对于这类表来说,没有commit和rollback的概念,相当于autocommit启用模式。

    另有一些命令,在执行之前会强制执行commit提交当前的活动事务。典型的例子,在数据定义语言(DDL)中,如果是会导致大量数据改变的操作,比如alter table。

    MySQL可以通过执行set transaction isolation level命令来设置隔离级别。新的隔离级别会在下一个事务开始时生效。

     2、在事务中混合使用存储引擎

    MySQL服务器层是不管理事务的,事务是由下层的存储引擎实现的。所以在同一个事务中,使用多种存储引擎是不可靠的。

     例如:在事务中混合使用事务型和非事务型的表(例如InnoDB和MyISAM表),正常提交情况下不会有什么问题。

    但当事务需要回滚时,非事务型的表上的变更就无法撤销,会导致数据库处于不一致状态,这种情况很难修复。事务的最终结果将无法确定。所以,为每张表选择合适的存储引擎非常重要。

    在非事务的表上执行事务操作时,MySQL不会有任何提醒,也不会报错,仅当需要回滚时才会发出警告“某些非事务型的表上的变更不能被回滚”。

    3、隐式和显示锁定

    InnoDB采用的是两阶段锁定协议。

    隐式锁定:在事务执行过程中,随时都可以执行锁定,锁只有在执行commit或rollback时才会被释放,并且所有锁时在同一时刻被释放。InnoDB会根据隔离级别在需要时候自动加锁。

    显示锁定:InnoDB支持通过特定的语句显示锁定,这些语句不属于SQL规范

    select ... lock in share mode
    select ... for update

    MySQL也支持lock tables和unlock tables语句,但这是在服务层实现的,和存储引擎无关。它们有自己的用途,并不能代替事务处理。如果应用需要用到事务时,还是应该选择事务型存储引擎。

    经常可以发现,应用已经将表从MyISAM转换到InnoDB,还是显示使用lock tables语句,这不但没有必要,还会严重影响性能,实际InnoDB的行级锁工作的更好。

    建议在任何时候不要执行lock tables。

    4、多版本并发控制(MVCC)

    MySQL的大多数事务型存储引擎实现都不是简单的行级锁。基于提升并发性能的考虑,他们一般都同时实现了多版本并发控制(MVCC)。

    不仅是MySQL,也包括Oracle、PostgreSQL等其他数据库系统也都实现了MVCC。但具体实现机制不尽相同,因为MVCC没有一个统一的实现标准。

    MVCC是行级锁的一个变种,但是它再很多情况下避免了加锁操作,因此开销更低。大都实现了非阻塞的读操作,写操作也只锁定必要的行。

    MVCC的实现,通过保存数据在某个时间点的快照来实现的。也就是说,不管需要执行多长时间,每个事物看到的数据都是一致的。根据事务开始的时间不同,每个书屋对同一张表,同一时刻看到的数据可能不一样。

    InnoDB的MVCC,是通过每行记录后面保存两个隐藏的列来实现的。这两个列,一个保存行的创建时的系统版本号,一个保存行的删除时的系统版本号。每开始一个新的事务,系统版本号就会自动递增。事务开始时刻的系统版本号会作为事务的版本号,用来和查询到的每行记录的版本号进行比较。repeatable read隔离级别下的MVCC

    select :InnoDB会根据以下两个条件检查每行记录,只有符合下述两个条件的记录,才会返回作为查询结果

    a、InnoDB只查找版本早于当前事务版本的数据行(行的版本号<=事务的系统版本号),这样可以确保事务读取的行,要么是在事务开始前已经存在的,要么是事务自身插入或者修改过的。

    b、行的删除版本要么未定义,要么大于当前事务版本号。这可以确保事务读取到的行,在事务开始前未被删除。

    insert:InnoDB为新插入的每一行保存当前系统版本号作为行版本号

    delete:InnoDB为删除的每一行保存当前系统版本号作为行删除标识

    update:InnoDB为插入一行新记录,保存当前系统版本号作为行版本号,同时保存当前系统版本号的原来的行作为行删除标识。

    举个栗子:

    -- 现在数据库有三条记录
    1 - - - 88 -
    2 - - - 88 -
    3 - - - 88 -
    -- 此时开启一个select事务,系统版本号+1=89,事务开始时刻版本号作为事务版本号=88
    -- 情况一、没有其他事务并行执行
    -- select 查询这三条记录发现 88=88 88=88 88=88 所以查询结果
    1 - - - 88 -
    2 - - - 88 -
    3 - - - 88 -
    -- 情况二、有其他事务并行执行
    -- 若在select事务开启同时开启了一个update事务,系统版本号=90,update事务=89
    -- update 1 - - - 89 -则
    1 - - - 89 -
    2 - - - 88 -
    3 - - - 88 -
    -- 此时select查询这三条记录 89>88 88=88 88=88,查询结果
    2 - - - 88 -
    3 - - - 88 -

    保存两个额外系统版本号,使大多数读操作都可以不用加锁。这样设计是的读数据操作很简单,性能很好,也能保证只会读取到符合标准的行。不足之处每行记录需要额外存储空间,需要更多行检查工作,以及额外的维护工作。

    注意:MVCC只能在repeatable read和 read committed两个隔离级别下工作。其他隔离级别不兼容,因为read uncommitted总是读取最新的数据行,而不是符合当前事务版本的行,serializable则会对读取行加锁

    5、InnoDB与MyISAM存储引擎

     InnoDB是MySQL默认的存储引擎,也是最重要、使用最广泛的存储引擎。特点是:

    ① 能处理大量的短期事务。

    ② 自动崩溃恢复特性,

    ③ 采用MVCC支持高并发,

    ④ 实现四个隔离级别,默认repeatable read,并通过间隙锁策略防止幻读的出现。间隙锁是的InnoDB不仅仅锁定查询涉及的行,还会对索引中的间隙进行锁定,防止幻影行的插入。

    ⑤ InnoDB基于聚簇索引建立的

    ⑥ 支持热备份

    ⑦ 读取磁盘数据时采用可预测性预读,能够自动在内存中创建hash索引以加速读操作的自适应哈希索引,能够加速插入操作的插入缓冲区。

    MyISAM不支持事务和行级锁,而且有一个毫无疑问的缺陷就是崩溃后无法安全恢复,适用于表小,可以忍受修复操作的表。特点是:

    ① 加锁与并发:MyISAM对整张表加锁,而不是针对行。

    ② 修复:对于MyISAM表,MySQL可以手工或者自动执行检查和修复操作。

    ③ 索引特性:支持索引,是一种基于分词创建的索引。

    ④ 延迟更新索引键 ,异步写入磁盘,但数据库奔溃或宕机会导致索引损坏,需要执行修复操作。

    抄自《高性能mysql》

  • 相关阅读:
    THUSC & 中考 & NOI 拉跨记
    Spring Security中的密码安全
    Spring Security 中的 CSRF和CORS
    Jacoco代码覆盖率
    Kafka拦截器
    shell遍历多个数组
    shell中的函数
    SpringSecurity权限控制
    SpringSecurity的@EnableWebSecurity注解
    SpringBoot配置自定义包扫描
  • 原文地址:https://www.cnblogs.com/wqff-biubiu/p/12347838.html
Copyright © 2011-2022 走看看