mysql 存储引擎 innodb 学习复习 之 锁

由于书是从图书馆借来的,记下一些学习的过程,便于以后查看

1. 锁是数据库区别于文件系统的重要特性之1,锁机制用于管理对共享文件的并发访问

   innodb使用的是行级锁

   myisam,使用的是表级锁,在并发条件下,读操作没有问题,但是并发插入会有性能上的影响

   sql server 2005之前的版本都是页级锁的,相对于myisam言,并发访问上性能有所提高,在2005以及之后,sql server 支持乐观并发和悲观并发,在乐观并发下执行行级锁,但实现方式和与innodb不相同,在sql server中,锁是一种稀有的资源,而在mysql innodb中,锁没有相关的开销,可以同时得到并发性和一致性

2. innodb的锁类型

    共享锁和排他锁

   共享锁 (S Lock): 允许事务读一行数据

   排他锁(X Lock):允许事务写或者修改一行数据

  ,可以在一行上使多个S锁,但是只要有X锁,就不能在加其他的锁了

  innodb存储引擎支持多粒度锁定,这种锁定允许在表级和行级上的锁同时存在,为了支持在不同粒度上架锁,innodb  提供了一种意向锁,意向锁是表级锁,且分为 意向共享锁和排他共享锁

3.  一致性非锁定读

    一致性非锁定读,是指innodb通过行多版本控制技术的方式来读取数据库中的数据,入如果读取的数据正在进行删除或者更新,这时读取操作不会因此等待行上的锁释放,而会去读取行的一个快照(快照指的是该行之前的版本的数据,该实现通过undo段实现),而因为undo段是用来在事务中回滚数据的,因此快照没有额外的开销,读取快照不需要加锁

    可以看出的是,一致性非锁定读,大大提高了数据读取的并发性,在innodb中,只是默认的方式,即读取不会占用和等待表上的锁,但是,在事务不同的隔离级别下,读取方式还是有所不同的,并不是每一个隔离级别下读取都是一致性的读。

4. 自增长和锁

 在innodb的内存结构中,对每一个含有自增长值的表都有一个自增长计数器,对含有自增长计数器的表进行插入时,这个计数器会被初始化,然后使用:

   select max(auto_inc_col) from table for update ,插入操作接着会依据这个自增长的计数器值加1赋予自增长列,这种实现方式称为:AUTO_INC Locking ,这种锁实际上是一种表级锁机制,为了提高插入的性能,锁不是在一个事务完成后才释放,而是在完成对自增长的值插入之后就立即释放,锁住的时间越短越好

  但是这种方式,在大量的插入操作中还是会有性能的问题,1) 对于自增长型的列的插入性能较差,必须等待前一个插入完成后才能插入下一个(虽然不用等待事务完成),2)对于insert select 的大数据量的插入,会影响插入的性能,因为另一个事务的插入可能会被阻塞

   

   从mysql 5.1.22起,innodb提供了一种 轻量级互斥量的自增长实现机制,便于提高并发的性能,使用一个参数 :innodb_autoinc_lock_mode,默认值为1

  在innodb 中,自增长值的列必须是索引,并且是索引的第一列,如果是第2列也会报错,另外,myisam是表级锁,不用考虑自增长并发插入

5. 外键和锁

   外键主要用于引用完整性的检查,在innodb中,如果没有对外键列加索引,innodb会隐式的对其加索引,这样可以避免表级锁 

   对于外键的插入,首先要查询父表中的记录,即select 父表,但对父表的select,不使用一致性非锁定读,因为这样会发生数据不一致性,innodb使用的是select ... lock in share mode ,主动对父表加一个S锁,这样,如果在父表上已经加了一个X锁,子表的操作就会被阻塞

6. 锁的算法

  innodb中有3种行锁的算法设计

  1) Record lock,单个行记录上的锁

  2)Gap Lock 间接锁,锁定的是一个范围,但不包含记录本身

  3) Next-key Lock : = Record lock + Gap lock ,锁定一个范围,并且包含记录本身

Record lock 总是会锁住索引记录,如果在建立存储引擎表时没有设置任何索引,innodb会使用隐式的主键进行锁定

在Next-key lock 算法下,对于行的查询,都是这种方式,对于不同的sql 查询,可能设置共享的 Next-key lock,或者 排他的 Next-key lock

7.  锁问题

锁会并发访问带来了性能上的提高,但是同时也会带来几个问题。1) 丢失更新。2) 脏读 3)不可重复读

1) 丢失更新

2) 脏读,指的是在不同事务下,可以读到另一个事务未提交的数据

3) 不可重复读,指的是在同一个事务中多次的读取同一个数据,在这个事务还没有结束之前,另外一个事务修改了这个数据,这是,在同一个事务的两次读之间,由于第2个事务的修改导致第一次事务两次读数据不同

脏数据和脏页的区别:

脏页指的是缓存池中已经修改但是还没有刷新到磁盘文件中,即数据库内存中的页和磁盘内存中的页数据是不一致的。而脏数据是指缓冲池中被修改的数据,但是还没有被提交。

对于脏页的读取是正常的,这并不影响数据的一致性,并且还因为是异步的,可以带来性能上的提高,而脏数据的读取,是一个事务读取到了另一个事务的数据,显然违反了事务的隔离性

脏读和不可重复读的区别:

脏读是读到了未提交的数据,而不可重复读读的是已经提交的,但是违反了事务的一致性要求 

8. 阻塞

因为不同锁之间的兼容性,在有些时候,一个事务中的锁需要等待另一个事务中的锁释放它所占用的资源,在innodb中使用的是Mutex数据结构来实现,在访问之前,需要使用mutex_enter函数进行申请,在资源访问完成之后立即执行mutex_exit(),但一个资源被一个事务占用时,另一个事务执行mutex_enter函数会发生阻塞

  innodb中,参数innodb_lock_wait_timeout用来设置超时的时间

9. 死锁

如果程序是串行的,那么搜索是不可能的,死锁只发生在并发访问情况下,innodb 中有一个后台thread,用来负责查看所有可能的死锁问题,并告知用户

10 锁升级

指的是当前锁的粒度降低,eg :将行级锁升级为 页级,页级升级为 表级

在innodb中,锁升级不会带来性能上的问题,1个锁的开销和100000个锁开销是相同的 

   

原文地址:https://www.cnblogs.com/hitwtx/p/2174297.html