MyISAM的表锁和InnoDB的行锁

锁机制是数据库中的一大重点,这篇文章就从锁的角度开始分析,然后比较MyISAMInnoDB存储引擎的相应特点,再分析两种数据库存储引擎所采用的锁机制。这篇文章的内容量还是可以的,主要集中在两个存储引擎间的特点比较(这里主要说的是MyISAM的表锁和InnoDB的行锁)比较

我们经常说到锁,那先讲讲锁的概念知识!

一、“锁”的概念

①锁,在现实生活中是为我们想要隐藏于外界所使用的一种工具。
②在计算机中,是协调多个进程或线程并发访问某一资源的一种机制。
③在数据库当中,除了传统的计算资源(CPU、RAM、I/O等等)的争用之外,数据也是一种供许多用户共享访问的资源。
④如何保证数据并发访问的一致性、有效性,是所有数据库必须解决的一个问题。
⑤锁的冲突也是影响数据库并发访问性能的一个重要因素。

二、MySQL中的锁

相对于其它数据库而言,MySQL的锁机制比较简单,其最显著的特点是不同的存储引擎支持不同的锁机制。比如,MyISAM和MEMORY存储引擎采用的是表级锁(table-level locking)。BDB存储引擎采用的是页面锁(page-level locking),但也支持表级锁。InnoDB存储引擎既支持行级锁(row-level locking),也支持表级锁,但默认情况下是采用行级锁。

锁的分类:
MySQL中锁的种类很多,大致分七种类型的锁,分别为共享/排它锁(Shared and Exclusive Locks)、意向锁(Intention Locks)、记录锁(Record Locks)、间隙锁(Gap Locks)、临键锁(Next-key Locks)、插入意向锁(Insert Intention Locks)、自增锁(Auto-inc Locks),这里只是说了一下共享/排它锁,关于锁的详细说明在其他的博客中。
1.根据操作分
(1)读锁(共享锁(S)):针对同一份数据,多个读取操作可以同时进行而不互相影响。
(2)写锁(排它锁(X)):当前写操作没有完成前,会阻断其他写锁和读锁。
(3)意向共享锁(IS):事务打算给数据行加行共享锁,事务在给一个数据行加共享锁前必须先取得该表的IS锁。
(4)意向排他锁(IX):事务打算给数据行加行排他锁,事务在给一个数据行加排他锁前必须先取得该表的IX锁。

说明:
1)共享锁和排他锁都是行锁,意向锁都是表锁,应用中我们只会使用到共享锁和排他锁,意向锁是mysql内部使用的,不需要用户干预。
2)对于UPDATE、DELETE和INSERT语句,InnoDB会自动给涉及数据集加排他锁(X);
对于普通SELECT语句,InnoDB不会加任何锁,事务可以通过以下语句显示给记录集加共享锁或排他锁。
共享锁(S):

SELECT * FROM table_name WHERE ... LOCK IN SHARE MODE;

排他锁(X):

SELECT * FROM table_name WHERE ... FOR UPDATE;

3)InnoDB行锁是通过给索引上的索引项加锁来实现的,因此InnoDB这种行锁实现特点意味着:只有通过索引条件检索数据,InnoDB才使用行级锁,否则,InnoDB将使用表锁!

2.根据粒度分
(1)表级锁:表级锁是MySQL中锁定粒度最大的一种锁,表示对当前操作的整张表加锁。它开销小,加锁快;不会出现死锁;锁定粒度大,发生锁冲突的概率最高,并发度最低。
(2)行级锁:行级锁是MySQL中锁定粒度最细的一种锁,表示只针对当前操作的行进行加锁。开销大,加锁慢;会出现死锁;锁定粒度最小,发生锁冲突的概率最低,并发度也最高。
(3)页级锁:页级锁是MySQL中锁定粒度介于行级锁和表级锁中间的一种锁。表级锁速度快,但冲突多。行级冲突少,但速度慢。所以取了折衷的页级,一次锁定相邻的一组记录。BDB支持页级锁。开销和加锁时间界于表锁和行锁之间;会出现死锁;锁定粒度界于表锁和行锁之间,并发度一般。
  
  从上述特点可见,很难笼统地说哪种锁更好,只能就具体应用的特点来说哪种锁更合适!!仅从锁的角度 来说:表级锁更适合于以查询为主,只有少量按索引条件更新数据的应用,如Web应用。而行级锁则更适合于有大量按索引条件并发更新少量不同数据,同时又有 并发查询的应用,如一些在线事务处理。

经上所述,对MySQL中的锁有基本的了解,下面开始说MyISAM的表锁和InnoDB的行锁!!
首先简述下myisam和innodb的特点区别

三、MyISAM和InnoDB的特点区别

3.1MyISAM特点(5.5 版本前默认引擎)
(1)MyISAM:只支持表级锁,不支持行锁。用户在操作myisam表时,select,update,delete,insert语句都会给表自动加锁 (读取时对需要读到的所有表加锁,写入时则对表加排他锁;)
(2)不支持事务
(3)不支持外键
(4)不支持崩溃后的安全恢复
(5)在表有读取查询的同时,支持往表中插入新纪录
(6)支持BLOB和TEXT的前500个字符索引,支持全文索引
(7)支持延迟更新索引,极大地提升了写入性能
(8)对于不会进行修改的表,支持 压缩表 ,极大地减少了磁盘空间的占用

注意:压缩表
  MySQL的MyISAM存储引擎支持压缩表空间,压缩后的表空间会减少,但是压缩后的表是只读的,不能插入和更新数据,如果需要更新,则需要解压后更新,再压缩 。
  可以使用 myisampack 对 MyISAM 表进行压缩。压缩表是不能进行修改的(除非先将压缩表解除压缩,修改数据,然后再次压缩)。压缩表可以极大地减少磁盘空间占用,因此也可以减少磁盘 I/O ,从而提升查询性能。压缩表也支持索引,但索引也是只读的。

MyISAM的压缩表测试:
(1)创建数据库,创建表并指定存储引擎为MyISAM,字符集为utf8

create database myisamdb;
use myisamdb;
create table myisam(id int unsigned auto_increment primary key, name varchar(20) not null )engine=myisam charset=utf8;

(2)将数据插入到表myisam表中

insert into myisam(name) values('联想tinkpad'),('Dell外星人'),('雷神玄武'),('mac pro');

(3)使用蠕虫复制(将查询出来的数据插入到指定表中)将myisam表空间迅速膨胀

mysql> insert into myisam select null,name from myisam;
Query OK, 262144 rows affected (1.00 sec)
Records: 262144  Duplicates: 0  Warnings: 0

(4)查看压缩前的myisam表空间大小

[root@ping myisamdb]# ls -lh myisam*
-rw-rw---- 1 mysql mysql 8.4K 2月  12 20:00 myisam.frm
-rw-rw---- 1 mysql mysql  12M 2月  12 20:06 myisam.MYD
-rw-rw---- 1 mysql mysql 5.2M 2月  12 20:06 myisam.MYI

(5)使用myisampack命令将myisam表空间进行压缩
myisampack+表名/文件名------对表空间进行压缩

[root@ping myisamdb]# myisampack  myisam
Compressing myisam.MYD: (524288 records)
- Calculating statistics
- - Compressing file
- 47.89%     
- Remember to run myisamchk -rq on compressed table

(6)查看压缩后的myisam表空间大小

[root@ping myisamdb]# ls -lh myisam*
-rw-rw---- 1 mysql mysql 8.4K 2月  12 20:00 myisam.frm  #表结构文件
-rw-rw---- 1 mysql mysql 6.0M 2月  12 20:06 myisam.MYD  #表空间文件
-rw-rw---- 1 mysql mysql 1.0K 2月  12 20:07 myisam.MYI  #表索引文件

(7)由于压缩后表空间会改变,导致索引找不到记录对应的索引位置,所以要恢复索引
myisamchk -rq 表名/文件名------检查恢复表的索引

[root@ping myisamdb]# myisamchk -rq myisam
- check record delete-chain
- - recovering (with sort) MyISAM-table 'myisam'
- Data records: 524288
- - Fixing index 1

(8)查看恢复的索引文件大小

[root@ping myisamdb]# ls -lh myisam*-rw-rw
---- 1 mysql mysql 8.4K 2月  12 20:00 myisam.frm-rw-rw
---- 1 mysql mysql 6.0M 2月  12 20:06 myisam.MYD-rw-rw
---- 1 mysql mysql 5.1M 2月  12 20:08 myisam.MYI

myisamchk+表名/文件名------解压缩

3.2InnoDB (5.5 版本后默认引擎)
注意:InnoDB的行锁,只是在WHERE的主键是有效的,非主键的WHERE都会锁全表的。
(1)支持行锁,采用MVCC来支持高并发,有可能死锁
(2)支持事务
(3)支持外键
(4)支持崩溃后的安全恢复
(5)不支持全文索引

3.3疑问解析
3.3.1是否保存数据库表中表的具体行数?(count(*)问题)
  InnoDB 中不保存表的具体行数,也就是说,执行select count() from table 时,InnoDB要扫描一遍整个表来计算有多少行,但是MyISAM只要简单的读出保存好的行数即可。
注意的是,当count(*)语句包含where条件时,两种表的操作是一样的。

3.3.2是否支持事务和崩溃后的安全恢复?
  MyISAM 强调的是性能,每次查询具有原子性,其执行数度比InnoDB类型更快,但不提供事务支持,一种非事务性的引擎,使得MyISAM引擎的MySQL可以提供高速存储和检索,以及全文搜索能力,适合数据仓库等查询频繁的应用;InnoDB 提供事务支持事务,外部键等高级数据库功能。 具有事务(commit)、回滚(rollback)和崩溃修复能力(crash recovery capabilities)的事务安全(transaction-safe (ACID compliant))型表。
  
3.3.3为什么说MyISAM执行数度比InnoDB类型更快?
INNODB在做SELECT的时候,要维护的东西比MYISAM引擎多很多:
(1)数据块,INNODB要缓存,MYISAM只缓存索引块, 这中间还有换进换出的减少;
(2)innodb寻址要映射到块,再到行,MYISAM记录的直接是文件的OFFSET,定位比INNODB要快
(3)INNODB还需要维护MVCC一致;虽然你的场景没有,但他还是需要去检查和维护
注意:MVCC (Multi-Version Concurrency Control)多版本并发控制
  InnoDB中通过为每一行记录添加两个额外的隐藏的值来实现MVCC,这两个值一个记录这行数据何时被创建,另外一个记录这行数据何时过期(或者被删除)。但是InnoDB并不存储这些事件发生时的实际时间,相反它只存储这些事件发生时的系统版本号。这是一个随着事务的创建而不断增长的数字。每个事务在事务开始时会记录它自己的系统版本号。每个查询必须去检查每行数据的版本号与事务的版本号是否相同。
让我们来看看当隔离级别是REPEATABLE READ时这种策略是如何应用到特定的操作的:
SELECT InnoDB必须每行数据来保证它符合两个条件:
  1)InnoDB必须找到一个行的版本,它至少要和事务的版本一样老(也即它的版本号不大于事务的版本号)。这保证了不管是事务开始之前,或者事务创建时,或者修改了这行数据的时候,这行数据是存在的。
  2)这行数据的删除版本必须是未定义的或者比事务版本要大。这可以保证在事务开始之前这行数据没有被删除。
  
3.4综上
  MyISAM更适合读密集的表,而InnoDB更适合写密集的的表。 在数据库做主从分离的情况下,经常选择MyISAM作为主库的存储引擎。如果需要事务支持,并且有较高的并发读取频率(MyISAM的表锁的粒度太大,所以当该表写并发量较高时,要等待的查询就会很多了),这时选InnoDB是不错的。如果你的数据量很大(MyISAM支持压缩特性可以减少磁盘的空间占用),而且不需要支持事务时,MyISAM是最好的选择。

3.4.1那么--------------如何选择???????
MyISAM适合:
(1)做很多count 的计算;
(2)插入不频繁,查询非常频繁,如果执行大量的SELECT,MyISAM是更好的选择;
(3)没有事务。
InnoDB适合:
(1)可靠性要求比较高,或者要求事务;
(2)表更新和查询都相当的频繁,并且表锁定的机会比较大的情况指定数据引擎的创建;
(3)如果你的数据执行大量的INSERT或UPDATE,出于性能方面的考虑,应该使用InnoDB表;
(4)DELETE FROM table时,InnoDB不会重新建立表,而是一行一行的删除;
(5)LOAD TABLE FROM MASTER操作对InnoDB是不起作用的,解决方法是首先把InnoDB表改成MyISAM表,导入数据后再改成InnoDB表,但是对于使用的额外的InnoDB特性(例如外键)的表不适用。
注意:创建每个表格的代码是相同的,除了最后的 TYPE参数,这一参数用来指定数据引擎。

3.4.2其他区别:
(1)对于AUTO_INCREMENT类型的字段,InnoDB中必须包含只有该字段的索引,但是在MyISAM表中,可以和其他字段一起建立联合索引。
(2)DELETE FROM table时,InnoDB不会重新建立表,而是一行一行的删除。
(3)LOAD TABLE FROM MASTER操作对InnoDB是不起作用的,解决方法是首先把InnoDB表改成MyISAM表,导入数据后再改成InnoDB表,但是对于使用的额外的InnoDB特性(例如外键)的表不适用。
(4)InnoDB存储引擎被完全与MySQL服务器整合,InnoDB存储引擎为在主内存中缓存数据和索引而维持它自己的缓冲池。
(5)对于自增长的字段,InnoDB中必须包含只有该字段的索引,但是在MyISAM表中可以和其他字段一起建立联合索引。
(6)清空整个表时,InnoDB是一行一行的删除,效率非常慢。MyISAM则会重建表。

上面对MyISAM和InnoDB进行了描述,下面对两个引擎用的锁再进行分析。

四、MyISAM的表锁和InnoDB的行锁

4.1MyISAM的表锁
4.1.1描述
MySQL的表锁有两种模式(即MyISAM引擎):
表共享读锁(Table Read Lock)和表独占写锁(Table Write Lock)。
  MyISAM在执行查询语句(SELECT)前,会自动给涉及的所有表加读锁,在执行更新操作(UPDATE、DELETE、INSERT等)前,会自动给涉及的表加写锁,这个过程并不需要用户干预,因此用户一般不需要直接用LOCK TABLE命令给MyISAM表显式加锁。

4.1.2加表锁方式(显式):
LOCK tables orders read local,order_detail read local;
SELECT SUM(total) FROM orders;
SELECT SUM(subtotal) FROM order_detail;
Unlock tables;
要特别说明以下两点内容:
(1)上面的例子在LOCK TABLES时加了‘local’选项,其作用就是允许其他用户在表尾插入记录。
(2)在用LOCK TABLES给表显式加表锁时,必须同时取得所有涉及表的锁,并且MySQL支持锁升级。也就是说,在执行LOCK TABLES后,只能访问显式加锁的这些表,不能访问未加锁的表;同时,如果加的是读锁,那么只能执行查询操作,而不能执行更新操作。其实,在自动加锁的情况下也基本如此,MyISAM总是一次性获得所需的全部锁,而InnoDB却是除单个SQL组成的事务外,锁是逐步获得的。这也正是MyISAM表不会出现死锁(Deadlock Free)的原因,一个session使用LOCK TABLE 命令给表film_text加了读锁,这个session可以查询锁定表中的记录,但更新或访问其他表都会提示错误;同时,另外一个session可以查询表中的记录,但更新就会出现锁等待。

4.1.3并发锁
在一定条件下,MyISAM也支持查询和操作的并发进行。
MyISAM存储引擎有一个系统变量concurrent_insert,专门用以控制其并发插入的行为,其值分别可以为0、1或2。
当concurrent_insert设置为0时,不允许并发插入。
当concurrent_insert设置为1时,如果MyISAM表中没有空洞时(即表中没有被删除的行),允许一个进程读表时,另一个进程在表尾并发插入记录。
当concurrent_insert设置为2时,无论MyISAM表中有没有空洞(也叫空数据块,这是由于删除行数据,但物理存储空间没有被删除而产生的),都允许在表尾并发插入记录。
  可以利用MyISAM存储引擎的并发插入特性,来解决应用中对同一表查询和插入锁争用。例如,将concurrent_insert系统变量为2,总是允许并发插入;同时,通过定期在系统空闲时段执行“OPTIONMIZE TABLE+表名”语句来整理空间碎片,收到因删除记录而产生的中间空洞。

注释
OPTIONMIZE TABLE进行碎片清理操作:
1.查看表占用的物理空间—du -sh
du -sh用法:
(1)du -sh .
对当前目录下所有的目录和文件的大小进行汇总,-s表示汇总,-h表示以KB, MB, GB, TB格式进行人性化显示
(2)du -sh *
对当前目录下每一个目录和文件的大小分别进行汇总
(3)du -sh bin
对指定的目录的大小进行汇总
(4)du -sh bin/*
对指定的目录下面所有的子目录和文件的大小分别进行汇总
(5)du -sh * | grep M或du -sh * | grep [M]
对当前目录下所有的目录和文件分别进行汇总,并使用"grep [M]"筛选出所有大小为M(兆)级别的目录和文件
(6)du -sh * | grep [MG]
筛选出大小为MB和GB级别的目录和文件
(7)du -sh * | grep [MG] | sort -nr
筛选出大小为MB和GB级别的目录和文件,并降序排序
2.进入控制台—mysql -u root -ppassword
3.使用OPTIMIZE TABLE进行碎片清理

4.2InnoDB的行锁
4.2.1描述
InnoDB实现了以下两种类型的行锁。
(1)共享锁(S):允许一个事务去读一行,阻止其他事务获得相同数据集的排他锁。共享锁只与共享锁兼容。
  共享锁也叫读锁,简称S锁,原理:一个事务获取了一个数据行的共享锁,其他事务能获得该行对应的共享锁,但不能获得排他锁,即一个事务在读取一个数据行的时候,其他事务也可以读,但不能对该数据行进行增删改。
(2)排他锁(X):允许获取排他锁的事务更新数据,阻止其他事务获得相同的数据集的共享锁和排他锁。排它锁与排它锁、共享锁都不兼容。
  排他锁也叫写锁,简称x锁,原理:一个事务获取了一个数据行的排他锁,其他事务就不能再获取该行的其他锁(排他锁或者共享锁),即一个事务在读取一个数据行的时候,其他事务不能对该数据行进行增删改查。

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

4.2.2加行锁方式(显示)
(1)共享锁(S):SELECT * FROM table_name WHERE … LOCK IN SHARE MODE
(2)排他锁(X):SELECT * FROM table_name WHERE … FOR UPDATE

4.2.3意向锁
为了允许行锁和表锁共存,实现多粒度锁机制,InnoDB还有两种内部使用的意向锁(Intention Locks),这两种意向锁都是表锁。
**意向共享锁(IS):**事务在给一个数据行加共享锁前必须先取得该表的IS锁。
**意向排他锁(IX):**事务在给一个数据行加排他锁前必须先取得该表的IX锁。

在InnoDB中,可以将上锁的对象看成一颗树,如果想要对最下层的对象加锁,也就是行锁,就必须要先对上层的对象上锁.也就是说,如果想要在一行上加写锁,首先要在表上加意向排它锁,其次在行所在的页上也加入意向排它锁,最后在那一行上加入排它锁.
注意:
  意向锁本身互相都是相互兼容的.意思就是如果表上加了意向共享锁,那么也可以继续在表上加入意向排它锁.
  
意向锁又是用来干什么的呢?
  意向锁主要是为了很容易的知道我即将要加锁的页或者表能不能被我加锁. 比如说,事务T1为表A中的一行记录加了排他锁,这个时候事务T2要做全表扫描,也就是说要在表级别加共享锁,这个时候,T2首先要判断这个表上是否能加共享锁.如果没有意向锁,那么T2就必须扫描全表,看是否能够加意向共享锁,也就是看看表中有没有任意一行加了排它锁,如果加了,就阻塞,等待,如果任意一行都没有排它锁,则可以加共享锁. 但是有了意向锁之后,因为如果要锁定某一行,就必须先在行锁的页和表上加意向锁.这个时候T2事务只需要看看表上是否有意向排他锁,如果有,则说明,表中有行记录被排它锁锁上了,阻塞,如果没有意向排它锁和排它锁,则自己就可以加锁.

4.2.4共享锁和意向共享锁,排他锁与意向排他锁的区别
共享锁和排他锁,系统在特定的条件下会自动添加共享锁或者排他锁,也可以手动添加共享锁或者排他锁。
意向共享锁和意向排他锁都是系统自动添加和自动释放的,整个过程无需人工干预。
共享锁和排他锁都是锁定的行记录,意向共享锁和意向排他锁锁定的是表。
注意:
InnoDb支持行锁和表锁,MyISAM只支持表锁
MyISAM的写请求的优先级比读请求的优先级高
MyISAM总是一次性获得所需的全部锁,要么全部满足,要么等待,因此不会出现死锁。
但是在InnoDB中,除单个SQL组成的事务外,锁是逐步获得的,这就决定了InnoDB发生死锁是可能的。

4.2.5InnoDB行锁实现方式?
  InnoDB行锁是通过索引上的索引项来实现的,这一点MySQL与Oracle不同,后者是通过在数据中对相应数据行加锁来实现的。InnoDB这种行锁实现特点意味着:只有通过索引条件检索数据,InnoDB才会使用行级锁,否则,InnoDB将使用表锁!
  在实际应用中,要特别注意InnoDB行锁的这一特性,不然的话,可能导致大量的锁冲突,从而影响并发性能。

行锁的三种算法(行锁的使用情景):
(1)Record Lock: 单个行记录上的锁。
  Record Lock总是会锁住索引记录,如果InnoDB存储引擎在建立标的时候没有设置索引,这个时候会用隐式的主键来锁定。
(2)Gap Lock: 间隙锁,锁定一个范围,但不包含本身。
  Gap Lock锁主要是用来锁住间隙的,也就是为了阻止多个事务将记录插入到同一范围内,这会导致幻读问题的产生。
(3)Next-Key Lock : Gap Lock+ Recork Lock,锁定一个范围,并且锁定记录本身。
  Next-Key Lock是结合了Gap Lock 和Record Lock的一种锁定算法。这种算法锁定的并不是单个值,而是一个范围,这个锁的出现也是为了防止幻读的出现
例如:
现在有一个索引: 10,11,13,20四个值。那么索引可能被Next-Key Locking的区间为:(-无穷,10),(10,11],(11,13],(13,20],(20,+无穷]。
通过这种锁,在自己锁定记录行的时候,还会锁住行记录之前的间隙。 分以下几种情况:
1)对于主键索引: Next-Key Lock会自动降级为Record Lock,单单锁住一个行记录。这里主要是为了提高并发性。
2)对于唯一辅助索引: 同主键索引一样。会自动降级为Record Lock锁。
3)对于普通的辅助索引: 会首先加上Next-KeyLock锁,并且在行记录后的空隙加上gap Lock锁。

4.2.6InnoDB什么时候使用表锁?
  于InnoDB表,在绝大部分情况下都应该使用行级锁,因为事务和行锁往往是我们之所以选择InnoDB表的理由。但在个别特殊事务中,也可以考虑使用表级锁。
第一种情况是:
  事务需要更新大部分或全部数据,表又比较大,如果使用默认的行锁,不仅这个事务执行效率低,而且可能造成其他事务长时间锁等待和锁冲突,这种情况下可以考虑使用表锁来提高该事务的执行速度。
第二种情况是:
  事务涉及多个表,比较复杂,很可能引起死锁,造成大量事务回滚。这种情况也可以考虑一次性锁定事务涉及的表,从而避免死锁、减少数据库因事务回滚带来的开销。
  当然,应用中这两种事务不能太多,否则,就应该考虑使用MyISAM表。

4.3总结
4.3.1对于MyISAM的表锁,主要有以下几点
(1)共享读锁(S)之间是兼容的,但共享读锁(S)和排他写锁(X)之间,以及排他写锁之间(X)是互斥的,也就是说读和写是串行的。
(2)在一定条件下,MyISAM允许查询和插入并发执行,我们可以利用这一点来解决应用中对同一表和插入的锁争用问题。
(3)MyISAM默认的锁调度机制是写优先,这并不一定适合所有应用,用户可以通过设置LOW_PRIPORITY_UPDATES参数,或在INSERT、UPDATE、DELETE语句中指定LOW_PRIORITY选项来调节读写锁的争用。
(4)由于表锁的锁定粒度大,读写之间又是串行的,因此,如果更新操作较多,MyISAM表可能会出现严重的锁等待,可以考虑采用InnoDB表来减少锁冲突。

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

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

  • 2
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值