1、MySQL锁基本介绍
锁是计算机协调多个进程或线程并发访问资源的一种机制。在数据库中,除了传统计算资源(如CPU、RAM、I/O等)的争用,数据也是很多用户共享的资源。如何保证并发数据访问的一致性和有效性是所有数据库都必须解决的问题,而锁冲突也是影响并发数据库访问性能的重要因素。从这个角度来看,锁对于数据库来说尤为重要和复杂。
与其他数据库相比,MySQL的锁机制比较简单,其最显着的特点就是不同的存储引擎支持不同的锁机制。例如:
表级锁:低开销,快速加锁;没有死锁;锁粒度大,锁冲突概率最高,并发度最低。
行级锁:高开销表行锁定的时候能查询么,慢锁;死锁;锁定粒度最小,锁冲突概率最低,并发度最高。
从以上特性可以看出,一般情况下很难说哪种锁更好,但是哪种锁更适合具体应用的特性!仅从锁的角度来看:表级锁更适用于专注于查询,只根据索引条件更新少量数据的应用,比如web应用;而行级锁更适合根据索引条件进行大量并发更新。数据和并发查询应用程序,例如一些在线事务处理 (OLTP) 系统。
2、MyISAM 表锁
MySQL 表级锁有两种模式:Table Read Lock 和 Table Write Lock )。
MyISAM表的读操作不会阻塞其他用户对同一张表的读请求,但会阻塞同一张表的写请求; MyISAM 表的写操作会阻塞同一张表的其他用户。表读写操作; MyISAM表的读写操作,写操作之间是串行的!
创建表语句:
CREATE
MyISAM 写锁阻塞读情况:
当一个线程获得一个表的写锁后,只有持有锁的线程才能更新表。其他线程的读写操作等到锁被释放。
MyISAM读阻塞写案例:
一个session使用锁表给表加了读锁,这个session可以锁表中的记录,但是更新和访问其他表会提示错误,同时另一个session可以查询表中的记录,但是更新会出现锁等待。
注意:
MyISAM 会在执行查询语句之前自动给所有涉及的表加读锁,然后执行更新操作。之前,写锁会自动添加到涉及的表中。此过程不需要用户干预。因此,用户一般不需要使用命令来显式锁定。在上面的例子中,使用锁来演示效果。
MyISAM 并发插入问题
MyISAM 表读写是串行的,一般来说,在一定条件下,MyISAM 还支持查询和插入操作的并发执行:
可以通过检查 table_locks_waited 和 table_locks_immediate 状态变量来分析系统上的表锁争用:
mysql
InnoDB 锁
1、事务及其 ACID 属性
事务是由一组 SQL 语句组成的逻辑处理单元。一个事务有 4 个属性,通常称为事务的 ACID 属性。
2、并发事务引起的问题
与串行处理相比表行锁定的时候能查询么,并发事务处理可以大大提高数据库资源的利用率,提高数据库系统的事务吞吐量,可以支持更多用户的并发操作,但同时会带来以下问题:
脏读:事务正在修改记录。在事务提交之前,这条记录的数据处于不一致的状态;此时,另一个事务也读取了相同的记录。如果不受控制,则第二个事务读取“脏”数据并相应地执行进一步处理。 ,导致未提交的数据依赖关系。这种现象形象地称为“脏读”
Non-repeatable read:一个事务读取了一些数据已经改变,或者一些记录被删除了!这种现象称为“不可重复读”。
幻读:一个事务根据相同的查询条件重新读取之前检索到的数据,但发现其他事务插入了符合其查询条件的新数据。这种现象称为“幻读”
以上问题都是数据库读一致性问题,可以通过事务隔离机制来保证。
数据库的事务隔离越严格,并发的副作用越小,但代价越大,因为事务隔离本质上就是将事务进行一定程度的串行化,需要根据具体的业务而定。需要决定使用哪个隔离级别
您可以通过检查 InnoDB_row_lock 状态变量来分析系统上的行锁争用情况:
'innodb_row_lock%'
3、InnoDB的行锁方式和加锁方式
共享锁:也称为读锁。允许一个事务读取一行,防止其他事务获取同一数据集的排他锁。如果事务T给数据对象A加了S锁,事务T可以读A但不能修改A,其他事务只能给A加S锁,不能加X锁,直到T释放A上的S锁。这样保证了其他事务可以读取A,但在T释放A上的S锁之前不能对A进行任何更改。
独占锁 (x):也称为写锁。允许获取排他锁的事务更新数据,防止其他事务获取同一数据集上的共享读锁和排他写锁。如果事务T给数据对象A加了X锁,那么事务T就可以读取A或者修改A,其他事务不能给A加任何锁,直到T释放A上的锁。
mysql InnoDB引擎默认数据修改语句:update、delete、insert会自动给涉及的数据加排他锁,select语句默认不会加任何锁类型,如果加排他锁可以使用select ...对于更新语句,添加共享锁可以在共享模式语句中使用 select ...lock。因此,排他锁的数据行不能修改其他事务中的数据,也不能通过for update和lock in share模式的锁查询数据,但是可以直接通过select ...from...查询数据,因为普通查询没有任何锁定机制。
InnoDB行锁实现方法
InnoDB的行锁是通过将索引项加在索引上来实现的,这一点与MySQL和Oracle不同,是通过数据块中对应的数据行加锁来实现的。 InnoDB的行锁实现特性意味着InnoDB只有在通过索引条件检索数据时才使用行级锁,否则InnoDB会使用表锁!
1、Innodb在无索引条件查询时使用表锁而不是行锁
(id int,name varchar
Session1 只给一行加了排他锁,但是当 session2 为其他行请求排他锁时,会有锁等待。原因是innodb只能使用没有索引的表锁。
2、为条件查询创建带索引的表,innodb使用行锁
(id int,name varchar
@ >
3、由于MySQL的行锁是对索引的锁,而不是对记录的锁,所以虽然访问的是不同行的记录,但如果使用相同的索引键,就会发生冲突。
alter table tab_with_index drop index id;
insert into tab_with_index values(1,'4');
虽然session2从session1访问不同的记录,但由于使用了相同的索引,所以需要等待锁
总结
对于MyISAM表锁,主要讨论以下几点:
对于InnoDB表,本文主要讨论以下几项内容:
在了解InnoDB锁特性后,用户可以通过设计和SQL调整来减少锁冲突和死锁,包括: