加锁的目的
- 对数据加锁是为了解决事务的隔离性问题,让事务之间相互不影响,每个事务进行操作的时候都必须先对数据加上一把锁,防止其他事务同时操作数据。提交或回滚事务会释放锁。
锁是基于什么实现的
-
数据库里面的锁是基于索引实现的,在Innodb中我们的锁都是作用在索引上面的,当我们的SQL命中索引时,那么锁住的就是命中条件内的索引节点(行锁),如果没有命中索引的话,那我们锁的就是整个索引树(表锁)。(insert语句怎么加锁?锁住整个表吗?)
1、如果一条sql 语句通过主键索引命中记录,Mysql 就会锁定这条语句命中的主键索引(或称聚簇索引); 2、如果一条语句通过非主键索引(或称辅助索引)命中记录,MySQL会先锁定该非主键索引,再锁定相关的主键索引。 3、如果没有索引,InnoDB 会通过隐藏的聚簇索引来对记录加锁。也就是说:如果不通过索引条件检索数据,那么InnoDB将对表中所有数据加锁,实际效果跟表级锁一样。
在实际应用中,要特别注意InnoDB行锁的这一特性,不然的话,可能导致大量的锁冲突,从而影响并发性能。 1、在不通过索引条件查询的时候,InnoDB 的效果就相当于表锁 2、当表有多个索引的时候,不同的事务可以使用不同的索引锁定不同的行,另外,不论 是使用主键索引、唯一索引或普通索引,InnoDB 都会使用行锁来对数据加锁。 3、由于 MySQL 的行锁是针对索引加的锁,不是针对记录加的锁,所以即便你的sql语句访问的是不同的记录行,但如果命中的是相同的被锁住的索引键,也还是会出现锁冲突的。 4、即便在条件中使用了索引字段,但是否使用索引来检索数据是由 MySQL 通过判断不同 执行计划的代价来决定的,如果 MySQL 认为全表扫 效率更高,比如对一些很小的表,它 就不会使用索引,这种情况下 InnoDB 将锁住所有行,相当于表锁。因此,在分析锁冲突时, 别忘了检查 SQL 的执行计划,以确认是否真正使用了索引
锁的分类
-
一、按锁的粒度划分,可分为
行级锁
、表级锁
、页级锁。
(mysql支持)在DBMS中,可以按照锁的粒度把数据库锁分为行级锁(INNODB引擎)、表级锁(MYISAM引擎)和页级锁(BDB引擎 )。 行级锁 行级锁是Mysql中锁定粒度最细的一种锁,表示只针对当前操作的行进行加锁。行级锁能大大减少数据库操作的冲突。其加锁粒度最小,但加锁的开销也最大。行级锁分为共享锁 和 排他锁。 特点:开销大,加锁慢;会出现死锁;锁定粒度最小,发生锁冲突的概率最低,并发度也最高。 支持引擎:InnoDB 行级锁定分为行共享读锁(共享锁)与行独占写锁(排他锁) ,如下所示,用法详见下一小节 共享锁(S):SELECT * FROM table_name WHERE ... LOCK IN SHARE MODE 排他锁(X):SELECT * FROM table_name WHERE ... FOR UPDATE 表级锁(偏向于读) 表级锁是MySQL中锁定粒度最大的一种锁,表示对当前操作的整张表加锁,它实现简单,资源消耗较少,被大部分MySQL引擎支持。最常使用的MYISAM与INNODB都支持表级锁定。表级锁定分为表共享读锁(共享锁)与表独占写锁(排他锁)。 特点:开销小,加锁快;不会出现死锁;锁定粒度大,发出锁冲突的概率最高,并发度最低。 支持引擎:MyISAM、MEMORY、InNoDB 分类:表级锁定分为表共享读锁(共享锁)与表独占写锁(排他锁),如下所示 lock table 表名 read(write),表名 read(write),.....; //给表加读锁或者写锁,例如 mysql> lock table employee write; Query OK, 0 rows affected (0.00 sec) mysql> show open tables where in_use>= 1; +----------+----------+--------+-------------+ | Database | Table | In_use | Name_locked | +----------+----------+--------+-------------+ | ttt | employee | 1 | 0 | +----------+----------+--------+-------------+ 1 row in set (0.00 sec) mysql> unlock tables; -- UNLOCK TABLES释放被当前会话持有的任何锁 Query OK, 0 rows affected (0.00 sec) mysql> show open tables where in_use>= 1; Empty set (0.00 sec) 页级锁 页级锁是MySQL中锁定粒度介于行级锁和表级锁中间的一种锁。表级锁速度快,但冲突多,行级冲突少,但速度慢。所以取了折衷的页级,一次锁定相邻的一组记录。BDB支持页级锁 特点:开销和加锁时间界于表锁和行锁之间;会出现死锁;锁定粒度界于表锁和行锁之间,并发度一般。
-
二、按锁级别划分,可分为
共享锁
、排他锁
(都是悲观锁)共享锁又称读锁,简称S锁。当一个事务对数据加上读锁之后,其他事务只能对该数据加读锁,而无法对数据加写锁,直到所有的读锁释放之后其他事务才能对其进行加写锁。 加了共享锁之后,无法再加排它锁,这也就可以避免读取数据的时候会被其它事务修改,从而导致重复读问题。 排他锁又称写锁,简称X锁;当一个事务对数据加上写锁之后,其他事务将不能再为数据加任何锁,直到该锁释放之后,其他事务才能对数据进行加锁。加了排他锁之后,其它事务就无法再对数进行读取和修改,所以也就避免了脏写和脏读的问题。update加锁类型为排他锁
-
三、按使用方式划分,可分为
乐观锁
、悲观锁
悲观锁就是在操作数据时,认为此操作会出现数据冲突,所以在进行每次操作时都要通过获取锁才能进行对相同数据的操作,这点跟java中的synchronized很相似,所以悲观锁需要耗费较多的时间。
乐观锁认为对同一个数据并发操作不会总发生,是小概率事件,因此不用每次对数据进行更新或者删除。
- 四、按锁状态划分,可分为
意向共享锁
、意向排它锁
意向锁是表级锁,其设计目的主要是为了在一个事务中揭示下一行将要被请求锁的类型。
意向锁的作用就是当一个事务在需要获取资源锁定的时候,如果遇到自己需要的资源已经被排他锁占用的时候,该事务可以需要锁定行的表上面添加一个合适的意向锁。意向锁是InnoDB自动加的,不需要用户干预。
如果自己需要一个共享锁,那么就在表上面添加一个意向共享锁。而如果自己需要的是某行(或者某些行)上面添加一个排他锁的话,则先在表上面添加一个意向排他锁
(1)意向共享锁(IS):事务打算给数据行共享锁;,事务在给一个数据行加共享锁前必须先取得该表的IS锁
(2)意向排他锁(IX)事务打算给数据行加排他锁;事务在给一个数据行加排他锁前必须先取得该表的IX锁
标签:事务,加锁,数据库,索引,共享,锁定,表级
From: https://www.cnblogs.com/d111991/p/16893541.html