mysql中IN(x,y,z)操作,是加行记录锁吗?

锁用来保证数据并发访问的一致性、有效性

MySQL的锁机制比较简单,其最显著的特点是不同的存储引擎支持不同的锁机制。MyISAM和MEMORY存储引擎采用的是表级锁(table-level locking)

MySQL这3种锁的特性可大致归纳如下:表级锁:开销小,加锁快;不会出现死锁;锁定粒度大,发生锁冲突的概率最高,并发度最低

行级锁:开销大,加锁慢;会出现死锁;锁定粒度最小,发生锁冲突的概率最低,并发度也最高。

页面锁:开销和加锁时间界于表锁和行锁之间;会出现死锁;锁定粒度界于表锁和行锁之间,并发度一般。

MYISAM存储引擎的锁机制

MyISAM存储引擎只支持表锁

如果Table_locks_waited的值比较高,则说明存在着较严重的表级锁争用情况

简单来说就是 :读锁可以被读操作共享,不影响读操作,但会影响写操作

写锁会影响所有的读写操作

MyISAM表的读和写是串行的,但这是就总体而言的。在一定条件下,MyISAM表也支持查询和插入操作的并发进行 MyISAM存储引擎有一个系统变量concurrent_insert,专门用以控制其并发插入的行为,其值分别可以为0、1或2。当 concurrent_insert 设置为0时,不允许并发插入。

当 concurrent_insert 设置为1时,如果MyISAM表中没有空洞(即表的中间没有被删除的行),MyISAM允许在一个进程读表的同时,另一个进程从表尾插入记录。这也是MySQL的默认设置。

当 concurrent_insert 设置为2时,无论MyISAM表中有没有空洞,都允许在表尾并发插入记录a. 可以利用MyISAM存储引擎的并发插入特性,来解决应用中对同一表查询和插入的锁争用。例如,将concurrent_insert系统变量设为2,总是允许并发插入; b. 同时,通过定期在系统空闲时段执行 OPTIMIZE TABLE语句来整理空间碎片,收回因删除记录而产生的中间空洞。

Unlock tables;上面的例子在LOCK TABLES时加了“local”选项,其作用就是在满足MyISAM表并发插入条件的情况下,允许其他用户在表尾并发插入记录,

在执行LOCK TABLES后,只能访问显式加锁的这些表,不能访问未加锁的表

同时,如果加的是读锁,那么只能执行查询操作,而不能执行更新操作

在自动加锁的情况下也基本如此,MyISAM总是一次获得SQL语句所需要的全部锁

由于MySQL认为写请求一般比读请求要重要,所以如果有读写请求同时进行的话,MYSQL将会优先执行写操作。 这样MyISAM表在进行大量的更新操作时(特别是更新的字段中存在索引的情况下),会造成查询操作很难获得读锁,从而导致查询阻塞。

我们可以通过一些设置来调节MyISAM的调度行为:通过指定启动参数low-priority-updates,使MyISAM引擎默认给予读请求以优先的权利

INNODB存储引擎的锁机制

获取InnoDB行锁争用情况

行锁不影响读操作,只影响写操作update ,delete 会自动给涉及到的数据集加上排他锁

普通的select则不加任何锁

但是如果当前事务也需要对该记录进行更新操作,则很有可能造成死锁,对于锁定行记录后需要进行更新操作的应用,应该使用SELECT… FOR UPDATE方式获得排他锁

InnoDB行锁是通过给索引上的索引项加锁来实现的,这一点MySQL与Oracle不同,后者是通过在数据块中对相应数据行加锁来实现的。 InnoDB这种行锁实现特点意味着:只有通过索引条件检索数据,InnoDB才使用行级锁,否则,InnoDB将使用表锁!

在多用户环境中,在同一时间可能会有多个用户更新相同的记录,这会产生冲突。这就是著名的并发性问题。

典型的冲突有:丢失更新:一个事务的更新覆盖了其它事务的更新结果,就是所谓的更新丢失。例如:用户A把值从6改为2,用户B把值从2改为6,则用户A丢失了他的更新。

脏读:当一个事务读取其它完成一半事务的记录时,就会发生脏读取。例如:用户A,B看到的值都是6,用户B把值改为2,用户A读到的值仍为6。

为了解决这些并发带来的问题。 我们需要引入并发控制机制。

并发控制机制悲观锁:假定会发生并发冲突,屏蔽一切可能违反数据完整性的操作。

乐观锁:假设不会发生并发冲突,只在提交操作时检查是否违反数据完整性。乐观锁不能解决脏读的问题。

乐观锁应用使用自增长的整数表示数据版本号。更新时检查版本号是否一致,比如数据库中数据版本为6,更新提交时version=6+1,使用该version值(=7)与数据库version+1(=7)作比较,如果相等,则可以更新,如果不等则有可能其他程序已更新该记录,所以返回错误。

使用时间戳来实现.基本思路与版本号一样

悲观锁的实现,往往依靠数据库提供的锁机制(也只有数据库层提供的锁机制才能真正保证数据访问的排他性,否则,即使在本系统中实现了加锁机制,也无法保证外部系统不会修改数据)。

#1.查询出商品信息,并为这一行加上排他锁

#2.根据商品信息生成订单

这样就通过数据库实现了悲观锁

此时在t_goods表中,id为1的 那条数据就被我们锁定了,其它的事务必须等本次事务提交之后才能执行

}

相必从事软件相关工作的各位同学,都或多或少的听过锁的概念,那么锁究竟是用来干什么的呢?

锁其实就是计算机用来协调多个进程或者线程并发访问某一资源的一种机制。

如果不加锁的话,大家一起操作某一共享资源,就会引起混乱。加锁是为了让并行操作变成串行操作,当某一进程或者线程操作资源的时候,我们用一把锁将后边的进程或者是线程拦截起来,防止他们干扰操作。当这一线程操作完毕之后,我们放行下一个线程对资源进行操作,这样互不影响有条不紊,极大的保证资源的安全性。

1.2 数据库中的锁?

数据库中的锁很好理解,数据就是一种共享资源,拥有操作权限的各个用户都可以操作数据。如果两个线程同时去修改数据库的某一个数据,比如库存,如果不加锁的话两个线程同时扣减库存,原来库存100,小明扣减10个库存,小红扣减5个,如果没有锁的控制,他们都是对100进行修改,那么结果就是90或者95,但是他俩一共扣了15个,正常库存是85才对。

如果不加锁的话,数据的一致性就没法得到保障。

MySQL数据库是众多数据库中的一种,随着去IOE化的发展,已及MySQL数据库本身的各种优势,MySQL数据库已经成为各大企业结构化数据库的首选,所以本篇文章我们大量篇幅讲MySQL的锁。

MySQL中的锁级别其实是取决于我们使用哪种存储引擎,不同的存储引擎锁也是有所区别

MySQL中不同锁级别的区别:

  • 表级锁: 开销小,加锁快;不会出现死锁;锁定粒度大,发生锁冲突的概率最高,并发度最低。

    表级锁更适合于以查询为主,只有少量按索引条件更新数据的场景;

  • 行级锁: 开销大,加锁慢;会出现死锁;锁定粒度最小,发生锁冲突的概率最低,并发度也最高。

    行级锁则更适合于有大量按索引条件并发更新少量不同数据,同时又有并发查询的场景。

  • 页面锁: 开销和加锁时间界于表锁和行锁之间;会出现死锁;锁定粒度界于表锁和行锁之间,并发度一般 .

    由于我们常用的存储引擎一般为InnoDB或者MyISAM,所以页面锁很少遇到

上边所讲述的只是锁的级别,数据库真正使用的是读锁,或者写锁。每个级别的锁都分为读锁,或者写锁。

这里的表锁指代MyISAM的表级锁,行锁指代InnoDB的行级锁,他们是我们最常用的,所以以他们为例进行介绍。

读锁不会阻塞其他用户的读操作,但是会阻塞写操作。

查询操作(SELECT)会自动加读锁。

写锁会阻塞其他用户对同一表的读和写操作。

执行更新操作 (UPDATE、DELETE、INSERT等)前,会自动给涉及的表加写锁

InnoDB与MyISAM的最大不同有两点:一是支持事务;二是使用行级锁。事务的加入让锁变的更为复杂,带入了不少新的问题。

InnoDB的行锁是基于索引实现的,如果不通过索引访问数据,InnoDB会使用表锁。

共享锁(S):又称读锁。

读锁不会阻塞其他事务的读,但是会阻塞其他事务写,不影响其它事务获取该事物的读锁。

读锁允许一个事务去读一行数据,并且阻止其他事务获得相同数据集的写锁。但是其他事务可以继续获得当前事务的读书,直到所有的读锁释放,才可以允许其他事务获取该数据集的写锁。

只要有事务读该行数据,就不能有事务进行写操作。

排他锁(X):又称写锁。

获取写锁的事务,可以更新数据,会阻塞其他事务获取该数据的读锁和写锁。

执行更新操作 (UPDATE、DELETE、INSERT等)都会自动给涉及到的数据加上排他锁。

事务打算给数据行加行共享锁,事务在给一个数据行加共享锁前必须先取得该表的IS锁。

事务打算给数据行加行排他锁,事务在给一个数据行加排他锁前必须先取得该表的IX锁。

不同情景使用不同算法实现的锁:

  • next KeyLocks锁,同时锁住记录(数据),并且锁住记录前后的间隙(Gap)
  • 间隙(Gap)锁,不锁记录,仅仅记录前后的间隙(Gap)
}

上篇说到数据库事务中的特性ACID和4个隔离级别,今儿就来看一下事务中的锁。

锁是MySQL在服务器层和存储引擎层的并发控制,锁可以保证数据并发访问的一致性、有效性;

锁冲突也是影响数据库并发访问性能的一个重要因素

MySQL有三种级别的锁:「表级锁、行级锁、页级锁」


表级锁行级锁业级锁特点开销小、加锁快开销大、加锁慢加锁时间介于其余两者之间是否会死锁否是是并发度粒度大、锁冲突概率最高、并发低粒度小、锁冲突概率低、并发高粒度介于其余两者之间、并发一般存储引擎Innodb、MyISAMInnodbBDB

「意向共享锁(IS):」

事务计划给数据行加行共享锁,加共享锁之前必先获取该锁

「意向排他锁(IX):」

事务打算给数据行加行排他锁,加排他锁之前必先获取该锁

特殊表锁,自增长计数器通过该“锁”来获得子增长计数器最大的计数值。

释放锁不需要添加参数,其会释放当前用户的所有锁。

1、给student表添加读锁,看当前用户和其他用户是否能插入数据:

当前用户:报错无法插入

root用户获取写锁:

然后试一下lsy用户能否获取相同表的写锁

当root用户释放写锁后:

lsy用户立马就获得了写锁:

共享锁(S)和排它锁(X)。

多个事务可以一起读,共享锁之间不互斥,共享锁会阻塞排它锁。

允许获得排他锁的事务更新数据,阻止其他事务取得相同数据集的共享读锁和排他写锁。

对于UPDATE、DELETE、INSERT语句,自动给相关数据加上排他锁

对于普通的SELECT语句,不加锁,属于快照读

排他锁:(这是我之前比较常用的)

通过对索引数据页上的记录(record)加锁实现的。

主要实现算法有 3 种:

单个行记录的锁(锁数据,不锁 Gap)。

间隙锁,锁定一个范围,不包括记录本身(不锁数据,仅仅锁数据前面的Gap)。

保证某个间隙内的数据在锁定期间不会发生任何变化。

当使用唯一索引进行搜索的时候,不会产生间隙锁

例如:student的id列是唯一索引

当使用非唯一索引或者没有索引进行搜索的时候,会产生间隙锁

根据检索条件向下寻找最靠近检索条件的记录值A作为左区间,向上寻找最靠近检索条件的记录值B作为右区间,即锁定的间隙为(A,B] 左开右闭。

例如:test的id列是没有索引

使用如下sql查询的时候

那么它的间隙范围就是(1,6]

如果在其他用户想往这区间插入数据就会阻塞,比如插入id是4的。

同时锁住数据,并且锁住数据前面的 Gap。

InnoDB 是逐行加锁的,极容易产生死锁。那么死锁产生的四个条件是什么呢?

一个资源每次只能被一个进程使用;

一个进程因请求资源而阻塞时,对已获得的资源保持不放;

进程已获得的资源,在没使用完之前,不能强行剥夺;

多个进程之间形成的一种互相循环等待资源的关系。

发生死锁后,会出现CPU使用率高,QPS急剧下降,回滚请求失败的情况

单次操作数据量不宜过多,涉及表尽量少。

减少表上索引,减少锁定资源。

「死锁情况下打印错误日志」

2、在事务2中删除test表中id=6的数据

3、在事务1中删除test表中id=6的数据

用于解决或者保证DDL操作与DML操作之间的一致性。

当对一个表做增删改查操作的时候,加 MDL 读锁;

当要对表做结构变更操作的时候,加 MDL 写锁。

读写锁之间、写锁之间是互斥的,用来保证变更表结构操作的安全性

根据上一条sql获取的线程id查询线程详细信息:

我是Liusy,一个喜欢健身的程序员。

获取更多干货以及最新消息,公_众_号:上古伪神

如果对您有帮助,点个关注、转发就是对我最大的支持!!!谢谢

}

我要回帖

更多关于 数据库主键和外键代码 的文章

更多推荐

版权声明:文章内容来源于网络,版权归原作者所有,如有侵权请点击这里与我们联系,我们将及时删除。

点击添加站长微信