mysql-innoDB-锁,

  虽然不能完全避免死锁,但可以使死锁的数量减至最少。将死锁减至最少可以增加事务的吞吐量并减少系统开销,因为只有很少的事务回滚,而回滚会取消事务执行的所有工作。由于死锁时回滚而由应用程序重新提交。
下列方法有助于最大限度地降低死锁:
(1)按同一顺序访问对象。
(2)避免事务中的用户交互。
(3)保持事务简短并在一个批处理中。
(4)使用低隔离级别。
(5)使用绑定连接。

在InnoDB加锁前,为什么要先start transaction

  innodb下锁的释放在事务提交/回滚之后,事务一旦提交/回滚之后,就会自动释放事务中的锁,innodb默认情况下autocommit=1即开启自动提交

检索条件使用索引和不使用索引的锁区别:

  检索条件有索引的情况下会锁定特定的一些行。

检索条件没有使用使用的情况下会进行全表扫描,从而锁定全部的行(包括不存在的记录)

  查看锁定的事务

行锁:

  InnoDB实现了两种类型额行级锁,共享锁和排它锁

88bf必发娱乐 1

  3.杀死进程

在InnoDB下 ,使用表锁要注意以下两点。

    (1)使用LOCK
TALBES虽然可以给InnoDB加表级锁,但必须说明的是,表锁不是由InnoDB存储引擎层管理的,而是由其上一层MySQL
Server负责的,仅当autocommit=0、innodb_table_lock=1(默认设置)时,InnoDB层才能知道MySQL加的表锁,MySQL
Server才能感知InnoDB加的行锁,这种情况下,InnoDB才能自动识别涉及表级锁的死锁;否则,InnoDB将无法自动检测并处理这种死锁。
    (2)在用LOCAK
TABLES对InnoDB锁时要注意,要将AUTOCOMMIT设为0,否则MySQL不会给表加锁;事务结束前,不要用UNLOCAK
TABLES释放表锁,因为UNLOCK
TABLES会隐含地提交事务;COMMIT或ROLLBACK不能释放用LOCAK
TABLES加的表级锁,必须用UNLOCK TABLES释放表锁,正确的方式见如下:
  例如:如果需要写表t1并从表t读   

SET AUTOCOMMIT=0;
LOCAK TABLES t1 WRITE, t2 READ, ...;
[do something with tables t1 and here];
COMMIT;
UNLOCK TABLES;

如果事务T对数据a加共享锁,则其他事务不能再加排它锁。获得共享锁的事务只能读数据

参考文献:

 [1] Baron Schwartz等 著,宁海元等 译 ;《高性能MySQL》(第3版);
电子工业出版社 ,2013

 [2] 简书博客,http://www.jianshu.com/p/a40f28dc29cd

 [3]CSDN博客,http://blog.csdn.net/zhanghongzheng3213/article/details/51721903

 [4]
CSDN博客,http://blog.csdn.net/dong976209075/article/details/8802778

 [5] CSDN博客,http://www.cnblogs.com/chenqionghe/p/4845693.html

 [6] CSDN博客,http://blog.csdn.net/psongchao/article/details/776172

 [7]
CSDN博客,http://blog.csdn.net/zhanghongzheng3213/article/details/51753010

 [8]
官网文档,https://dev.mysql.com/doc/refman/5.6/en/lock-tables.html

http://www.bkjia.com/Mysql/1230315.htmlwww.bkjia.comtruehttp://www.bkjia.com/Mysql/1230315.htmlTechArticlemysql-innoDB-锁, 在InnoDB加锁前,为什么要先start
transaction
innodb下锁的释放在事务提交/回滚之后,事务一旦提交/回滚之后,就会自动释放事务…

  1.查询是否锁表

  共享锁和意向共享锁,排他锁与意向排他锁的区别:

  • 共享锁和排他锁,系统在特定的条件下会自动添加共享锁或者排他锁,也可以手动添加共享锁或者排他锁。
  • 意向共享锁和意向排他锁都是系统自动添加和自动释放的,整个过程无需人工干预。
  • 共享锁和排他锁都是锁的行记录,意向共享锁和意向排他锁锁定的是表。

 

悲观锁与乐观锁的实现方式:

  悲观锁的实现依靠的是数据库提供的锁机制来实现,例如select * from
news where id=12 for
update,而乐观锁依靠的是记录数据版本来实现,即通过在表中添加版本号字段来作为是否可以成功提交的关键因素。

88bf必发娱乐 2

4.共享锁(读锁),读取操作创建的额锁。其他用户可以并发读取数据,但不能对其进行修改,直到已释放所有共享锁

 锁的实现方式:

  在MySQL中,行级锁并不是直接锁记录,而是锁索引。索引分为主键索引和非主键索引两种,如果一条sql语句操作了主键索引,MySQL就会锁定这条主键索引;如果一条语句操作了非主键索引,MySQL会先锁定该非主键索引,再锁定相关的主键索引。

  InnoDB行锁是通过给索引项加锁实现的,如果没有索引,InnoDB会通过隐藏的聚簇索引来对记录加锁。也就是说:如果不通过索引条件检索数据,那么InnoDB将对表中所有数据加锁,实际效果跟表锁一样

8.死锁,两个或两个以上进程,因争夺资源而造成一种互相等待的现象。

mysql-innoDB-锁,

SELECT * FROM INFORMATION_SCHEMA.INNODB_LOCK_WAITS;

写锁:

  写锁是排他的,也就是说一个写锁会阻塞其他的写锁和读锁。另外写锁比读锁有更高的优先级,因此一个写锁请求可能会被插入到读锁
队列的前面,但是读锁则不肯能插入到写锁的前面

1.乐观锁:用数据版本记录机制实现。
为数据增加一个版本表示,一般是数据库增加一个version字段。读取数据时,把version字段一起独处,每更新一次,version+1.
提交时,提交版本必须大于当前版本才能执行更新。

 死锁:

  我们说过MyISAM中是不会产生死锁的,因为MyISAM总是一次性获得所需的全部锁,要么全部满足,要么全部等待。而在InnoDB中,锁是逐步获得的,就造成了死锁的可能。

   
 发生死锁后,InnoDB一般都可以检测到,并使一个事务释放锁回退,另一个获取锁完成事务。但在涉及外部锁,或涉及锁的情况下,InnoDB并不能完全自动检测到死锁,这需要通过设置锁等待超时参数innodb_lock_wait_88bf必发娱乐,timeout来解决。需要说明的是,这个参数并不是只用来解决死锁问题,在并发访问比较高的情况下,如果大量事务因无法立即获取所需的锁而挂起,会占用大量计算机资源,造成严重性能问题,甚至拖垮数据库。我们通过设置合适的锁等待超时阈值,可以避免这种情况发生。

  如果系统资源充足,进程的资源请求都能够得到满足,死锁出现的可能性就很低,否则就会因争夺有限的资源而陷入死锁。其次,进程运行推进顺序与速度不同,也可能产生死锁。
产生死锁的四个必要条件:
(1) 互斥条件:一个资源每次只能被一个进程使用。
(2)
请求与保持条件:一个进程因请求资源而阻塞时,对已获得的资源保持不放。
(3) 不剥夺条件:进程已获得的资源,在末使用完之前,不能强行剥夺。
(4) 循环等待条件:若干进程之间形成一种头尾相接的循环等待资源关系。

共享锁(S):

  共享锁也叫读锁,一个事务获取了一个数据行的共享锁,其他事务能获得该行对应的共享锁,但不能获得排他锁,即一个事务在读取一个数据行的时候,其他事务也可以读,但不能对该数据行进行增删改

  设置共享锁: SELECT …. LOCK IN SHARE MODE;

3.悲观锁设计到的另外两个锁概念:共享锁和排他锁都是悲观锁的一种实现。

意向排它锁(IX):

  通知数据库接下来需要施加什么锁并对表加锁。如果需要对记录A加排他锁,那么此时innodb会先找到这张表,对该表加意向排他锁之后,再对记录A添加共享锁。也就是说一个数据行加排它锁前必须先取得该表的IX锁

  查看当前等锁的事务

行锁分为三种情况:

  Record Lock:对索引项加锁,即锁定一条记录。

  Gap Lock:对索引项之间的 ‘间隙’
、对第一条记录前的间隙或最后一条记录后的间隙加锁,即锁定一个范围的记录,不包含记录本身

  Next-key Lock:锁定一个范围的记录并包含记录本身(上面两者的结合)

  注意:InnoDB默认级别是repeatable-read(重复读)级别。ANSI/IOS
SQL标准定义了4种事务隔离级别:未提交读(read uncommitted),提交读(read
committed),重复读(repeatable read),串行读(serializable)

6.行锁,给某一行,也就是某一条记录加锁。基于索引的,所以如果sql语句用不到索引也就用不到行锁,只会用到表锁。

 总结:

  对于InnoDB表,主要有以下几点  
  (1)InnoDB的行销是基于索引实现的,如果不通过索引访问数据,InnoDB会使用表锁。
    (2)InnoDB间隙锁机制,以及InnoDB使用间隙锁的原因。  
  (3)在不同的隔离级别下,InnoDB的锁机制和一致性读策略不同。  
  (4)MySQL的恢复和复制对InnoDB锁机制和一致性读策略也有较大影响。  
  (5)锁冲突甚至死锁很难完全避免。        
在了解InnoDB的锁特性后,用户可以通过设计和SQL调整等措施减少锁冲突和死锁,包括:

  • 尽量使用较低的隔离级别
  • 精心设计索引,并尽量使用索引访问数据,使加锁更精确,从而减少锁冲突的机会。
  • 选择合理的事务大小,小事务发生锁冲突的几率也更小。
  • 给记录集显示加锁时,最好一次性请求足够级别的锁。比如要修改数据的话,最好直接申请排他锁,而不是先申请共享锁,修改时再请求排他锁,这样容易产生死锁。
  • 不同的程序访问一组表时,应尽量约定以相同的顺序访问各表,对一个表而言,尽可能以固定的顺序存取表中的行。这样可以大减少死锁的机会。
  • 尽量用相等条件访问数据,这样可以避免间隙锁对并发插入的影响。
  • 不要申请超过实际需要的锁级别;除非必须,查询时不要显示加锁。
  • 对于一些特定的事务,可以使用表锁来提高处理速度或减少死锁的可能。

 

Gap Lock和Next-key Lock的区别:

  Next-Key
Lock是行锁与间隙锁的组合,这样,当InnoDB扫描索引记录的时候,会首先对选中的索引记录加上行锁(Record
Lock),再对索引记录两边的间隙加上间隙锁(Gap
Lock)。如果一个间隙被事务T1加了锁,其它事务是不能在这个间隙插入记录的。

  行锁防止别的事务修改或删除,Gap锁防止别的事务新增,行锁和GAP锁结合形成的Next-Key锁共同解决了RR界别在写数据时的幻读问题。

kill id

读锁:

  读锁是共享的,或者说是相互不阻塞的。多个用户在同一时刻可以同时读取同一个资源,而互不干扰。

二、解决方法

意向共享锁(IS):

  通知数据库接下来需要施加什么锁并对表加锁。如果需要对记录A加共享锁,那么此时innodb会先找到这张表,对该表加意向共享锁之后,再对记录A添加共享锁。也就是说一个数据行加共享锁前必须先取得该表的IS锁

SELECT * FROM INFORMATION_SCHEMA.INNODB_TRX;

表锁:

  InnoDB还有两个表锁:意向共享锁(IS),意向排它锁(IX)

show processlist

乐观锁:

  乐观锁,也叫乐观并发控制,它假设多用户并发的事务在处理时不会彼此互相影响,各事务能够在不产生锁的情况下处理各自影响的那部分数据。在提交数据更新之前,每个事务会先检查在该事务读取数据后,有没有其他事务又修改了该数据。如果其他事务有更新的话,那么当前正在提交的事务会进行回滚。

7.表锁。innodb引擎在用不到索引也就是用不到行锁的时候,行锁会变成表锁。

何时在InnoDB中使用表锁:

  InnoDB在绝大部分情况会使用行级锁,因为事务和行锁往往是我们选择InnoDB的原因,但是有些情况下我们也考虑使用表级锁

  • 当事务需要更新大部分数据时,表又比较大,如果使用默认的行锁,不仅效率低,而且还容易造成其他事务长时间等待和锁冲突。
  • 事务比较复杂,很可能引起死锁导致回滚。

 

  有多种方法可以避免死锁,这里介绍常见的三种:

   ps:如果出现死锁,可以用SHOW INNODB
STATUS命令来确定最后一个死锁产生的原因和改进措施。

  2.查询所有进程

排它锁(X):

  排它锁也叫写锁,一个事务获取了一个数据行的排他锁,其他事务就不能再获取该行的其他锁(排他锁或者共享锁),即一个事务在读取一个数据行的时候,其他事务不能对该数据行进行增删改查

  设置排它锁:SELECT …. FOR UPDATE

  注意点:

  • 对于select
    语句,innodb不会加任何锁,也就是可以多个并发去进行select的操作,不会有任何的锁冲突,因为根本没有锁。
  • 对于insert,update,delete操作,innodb会自动给涉及到的数据加排他锁,只有查询select需要我们手动设置排他锁。

一:分类

悲观锁:

  悲观锁,也叫悲观并发控制,当事务A对某行数据应用了锁,并且当这个事务把锁释放后,其他事务才能够执行与该锁冲突的操作,这里事务A所施加的锁就叫悲观锁。享锁和排他锁(行锁,间隙锁,next-key
lock)都属于悲观锁

2.悲观锁,在操作数据时,认为此操作会出现数据冲突,所以在进行每次操作时都要通过获取锁才能进行对相同数据的操作。

三、产生和避免

SELECT * FROM INFORMATION_SCHEMA.INNODB_LOCKS;

5.排它锁(写锁),加锁之后,可以读也可以写,其他时候不能再加锁。

show OPEN TABLES where In_use > 0;

  或者先查看事务