zoukankan      html  css  js  c++  java
  • 隔离级别

     mysql innodb默认的事务处理级别是'REPEATABLE-READ',也就是可重复读

    对于非锁定读取,同一事务中两次读取的是相同的快照

    对于锁定读取(select带for update或者for share)或者update或者delete语句,根据语句中使用的是唯一性索引条件还是范围类型查询条件:
    对于具有唯一搜索条件的唯一索引, InnoDB仅锁定找到的索引记录,而不是 之前的间隙。
    对于其他搜索条件,InnoDB 使用间隙锁或 下一键锁定锁定扫描的索引范围, 以阻止其他会话插入范围所覆盖的间隙。

    read uncommit(脏读):

    一个事务可以读到另一个事务中未提交的数据

    read commit(不可重复读):

    大多数数据库系统都会默认设置该级别,
    一个事务只能看到另一个事务提交过的数据,但是有另一个问题,如果A事务开始后第一个查询与第二次查询中间,有B事务对A事务中两次查询的数据做了修改,则会出现A事务第一次和第二次查询的数据不一致的问题

    repeatable read(可重复读):

    解决了不可重复读的问题,该级别解决了同一事物中多次读取同样记录的结果是一致的:A事务根据条件M第一次读取10行记录,同时对10条记录增加行锁,这样其他事务就不能访问了,A事务根据条件M第二次读取相同的10条记录,由于10条记录都加了行锁,所以保证10条记录是一样的 ,但是不能保证在A事务根据条件M的两次查询中,B事务增加了一条也符合条件M记录,这样在A事务第二次查询中会查询11条符合的记录,(幻读)
     
    可重复读不能解决的问题是:A事务读取了一个范围的记录,另B事务在A事务执行期间在A读取的记录查询一个一条记录,这种现象称为幻读
    解决幻读的方法之一是serializable(可串行化)、锁表
    解决幻读的方式是MVCC(多版本并发控制可以解决幻读问题)

    serializable(可串行化)(加锁读):

    最高的隔离级别,强制事务串行执行。
     
    --------------------------------mysql官网截取---------------------------------------
    默认InnoDB隔离级别 REPEATABLE READ通过允许事务读取具有独占锁的行来实现更高的 并发性,这种技术称为一致读取。
    共享锁:这种锁允许其他事物读取被共享锁锁定的行,同时也可以获得被其他共享锁锁定的行(只能读,不能写)
    独占锁:这种锁会阻止其他事物锁定已经被锁定的行,根据事务的隔离级别这种锁可以其他事物写被锁定的行,或者阻止其他事物读被锁定的行。
    行锁:行锁是在索引记录的锁,例如SELECT c1 FROM t WHERE c1 = 10 FOR UPDATE; 可以阻止其他事物对c1=10记录的修改、删除或者新增。行锁通常锁索引记录,如果没有表定义索引,则innodb会默认创建隐藏的索引,并且使用这个隐藏的索引用于行锁。
    间隙锁:多个间隙锁可以共存,一个事务占用了记录的间隙锁,不影响其他事务占用该间隙锁。
    间隙锁在索引记录之间或者索引前、索引后加锁,例如: SELECT c1 FROM t WHERE c1 BETWEEN 10 and 20 FOR UPDATE;会阻止其他事务插入c1=15的记录,无论使用有c1=15的记录,因为该范围内的所有值之间都加了间隙锁,
    间隙可能跨越单个索引值,多个索引值,甚至可能为空。
    间隙锁只用于一些事务级别,而其他级别不使用
    间隙锁与行锁的优先级:例如SELECT * FROM child WHERE id = 100;如果id是唯一索引,则id=100使用行锁,如果id不是索引则使用间隙锁。
    使用read commited级别时,会禁用间隙锁。
    下一键锁:下一键锁定是索引记录上的记录锁定和索引记录之前的间隙上的间隙锁定的组合。默认情况下,InnoDB以 REPEATABLE READ事务隔离级别运行。在这种情况下,InnoDB使用下一键锁进行搜索和索引扫描,这会阻止幻像行
     
     幻读进一步说明:
    幻读:同一个条件下在不同时间段产生不同的记录结果
    为了防止幻像,InnoDB使用一种称为下一键锁定的算法,该算法将索引行锁定与间隙锁定相结合。 InnoDB执行行级锁定时,它在搜索或扫描表索引时,会在遇到的索引记录上设置共享锁或排它锁。因此,行级锁实际上是索引记录锁。此外,索引记录上的下一键锁定也会影响该索引记录之前的 “ 间隙 ”。也就是说,下一键锁定是索引记录锁定加上索引记录之前的间隙上的间隙锁定。如果一个会话具有共享或独占锁定记录R在索引中,另一个会话不能R在索引顺序之前的间隙中插入新的索引记录 。当InnoDB扫描索引,它也可以锁定在指数的最后一个记录之后的间隙。恰好在前面的示例中发生:为了防止任何插入到表中 id大于100的锁,设置的锁 InnoDB包括在id值102之后的间隙上的锁 。
     
    验证使用下一键锁,阻止了幻读发生。
    在A回话中执行:
    start transaction;
    SELECT * FROM white_user WHERE id > 33 FOR UPDATE;
    (前提A回话)在B回话中执行:(id是自增主键,该insert新增后,id一定大于33)
    insert into white_user(teacheremail) values('3333');
    发现不能执行
    (前提A回话)在C回话中执行:(新增之前id=23已经被删除,指定id=23)
    insert into white_user(id,teacheremail) values(23,'3333');
    执行成功
    (前提A回话)在D回话中执行:
    update white_user set teacheremail=1111 where id=1;
    也可以执行成功
     
     
    1.查看当前会话隔离级别
    select @@tx_isolation;
    2.查看系统当前隔离级别
    select @@global.tx_isolation;
    3.设置当前会话隔离级别
    set session transaction isolatin level repeatable read;
    4.设置系统当前隔离级别
    set global transaction isolation level repeatable read;
    5.设置当前回话不自动提交
    set autocommit = 0
     
     
     
    Locking and Transactions
    LOCK TABLES acquires two locks on each table if innodb_table_locks=1 (the default). In addition to a table lock on the MySQL layer, it also acquires an InnoDB table lock. Versions of MySQL before 4.1.2 did not acquire InnoDB table locks; the old behavior can be selected by setting innodb_table_locks=0. If no InnoDB table lock is acquired, LOCK TABLES completes even if some records of the tables are being locked by other transactions.
     
    In MySQL 8.0, innodb_table_locks=0 has no effect for tables locked explicitly with LOCK TABLES ... WRITE. It does have an effect for tables locked for read or write by LOCK TABLES ... WRITE implicitly (for example, through triggers) or by LOCK TABLES ... READ.
     
    All InnoDB locks held by a transaction are released when the transaction is committed or aborted. Thus, it does not make much sense to invoke LOCK TABLES on InnoDB tables in autocommit=1 mode because the acquired InnoDB table locks would be released immediately.
     
    You cannot lock additional tables in the middle of a transaction because LOCK TABLES performs an implicit COMMIT and UNLOCK TABLES.
     
    The limit on data-modifying transactions is 96 * 1023 concurrent transactions that generate undo records. 32 of 128 rollback segments are assigned to non-redo logs for transactions that modify temporary tables and related objects. This means that the maximum number of concurrent data-modifying transactions is 96K. The 96K limit assumes that transactions do not modify temporary tables. If all data-modifying transactions also modify temporary tables, the limit is 32K concurrent transactions.
    --------------------------------mysql官网截取---------------------------------------
     
     引用其他博主的描述:
    不可重复读重点在于update和delete,而幻读的重点在于insert。
    如果使用锁机制来实现这两种隔离级别,在可重复读中,该sql第一次读取到数据后,就将这些数据加锁,其它事务无法修改这些数据,就可以实现可重复 读了。但这种方法却无法锁住insert的数据,所以当事务A先前读取了数据,或者修改了全部数据,事务B还是可以insert数据提交,这时事务A就会 发现莫名其妙多了一条之前没有的数据,这就是幻读,不能通过行锁来避免。需要Serializable隔离级别 ,读用读锁,写用写锁,读锁和写锁互斥,这么做可以有效的避免幻读、不可重复读、脏读等问题,但会极大的降低数据库的并发能力。
    所以说不可重复读和幻读最大的区别,就在于如何通过锁机制来解决他们产生的问题。
     
     
     
     
     
     
     
     
     
     
     
     
     
     
     
     
     
     
     
     
     
     
     
     
     
    收藏文章数量从多到少与“把书读薄”是一个道理
  • 相关阅读:
    滚动条滚动方向
    阶乘函数-尾递归
    返回顶部
    CommonJS
    vuessr
    随机字符串
    indexedDB
    深层次选择器
    Vue3.0简单替代Vuex
    shell 学习笔记
  • 原文地址:https://www.cnblogs.com/use-D/p/9544993.html
Copyright © 2011-2022 走看看