原文地址:http://www.linzichen.cn/article/1571531799593484288

在程序开发中,当多个线程并发操作共享数据时,我们需要保证在任何时刻最多只能有一个线程在操作,以保证数据的 完整性一致性。比如在 JAVA 中,单体应用有 synchornizedReentrantLock锁,分布式应用有 分布式锁。同样在数据库中,用户数据作为一种共享资源,同样也提供对应的锁机制。

一、多事务访问的几种情况

并发事务访问相同记录的情况大致可以分为三种:

读读写写读写或写读

1.1 读 - 读

即并发事务相继读取相同的记录。读取操作不会对记录有任何影响,也不会引起什么问题,所以允许这种情况发生。

1.2 写 - 写

即并发事务相继对相同的记录做出改动。

在这种情况下会发生脏写的问题,所以在多个事务对一条记录做改动时,需要让它们 排队执行。排队过程就是通过来实现的。它们的流程为:

1、当事务 T1 想对记录改动时,会先判断内存中是否存在当前记录的锁。如果不存在,则 T1会在内存中生成一个锁结构,与当前记录关联。

锁结构中有很多信息,其中有两个重要的属性:

  • trx信息:当前锁结构是哪个事务生成的。
  • is_waiting:当前事务是否是等待状态。

2、在 T1事务提交之前,另一个事务T2也要对当前记录做改动,但是此时内存中,还存在 T1事务的锁与当前记录关联,所以 T2也会生成一条与当前记录关联的锁结构,只不过 T2锁结构的 is_waiting属性值是 true,代表当前事务需要等待。

3、在事务 T1提交之后,就会把它生成的锁结构释放掉,然后看看内存中有没有别的事务锁在等待状态,发现 T2在等待之后,会把 T2对应的锁结构的 is_waiting属性改为 false,然后把该事务的线程唤醒,让它继续执行,此时事务 T2就算获取到锁了,可以继续执行。

脏写:一个事务修改了另一个事务未提交的数据。
比如事务T1进行了 insert但还未提交:
insert into t1 (id, name) values (1, '张三');
但事务 T2T1未提交的数据进行了修改:
update t1 set name = '李四' where id = 1;
如果T1进行了回滚,那此数据实际是不存在的。这种现象就是脏写,数据库中任何隔离级别都不允许此情况发生。

1.3 读 - 写 或 写 - 读

即一个事务进行读操作,另一个进行写操作。这种情况下可能发生 脏读不可重复读幻读的问题。

脏读:事务T1读了另一个事务T2还未提交的数据。比如 T2进行了insert但还未提交,此时 T1事务select到了此数据,这种现象就是脏读。
不可重复读:事务T1查询了id=1的记录的name字段是张三,此时事务T2对此记录的name改为了 李四,并且提交了。然后 T1再次查询时发现 name字段变成了 李四。前后读取的数据不一致,这种现象就是不可重复读。
幻读:事务 T1查询了表中id>1的记录有3条,此时事务 T2进行了 insert操作(id > 1)并且提交,然后T1再次查询时记录变成了 4条。前后读取的记录数不一致。这种现象就是幻读。

二、并发事务问题解决方案

为了解决 脏读不可重复读幻读 这些现象的发生,其实有两种可选的解决方法。

MVCC

读操作利用 MVCC,写操作加锁

所谓MVCC,就是通过 undo日志的版本链和 ReadView快照构成的多版本并发控制,它实际读取的是版本链中最新提交的数据,而非其他活动事务正在操作的数据,这样就可以避免因为活动中事务的写,造成的一系列的问题。MVCC不是本文的重点内容,所以这里不做过多介绍了。

加锁

脏读是因为事务 T1读到了事务T2写入的未提交的数据。那我们只要在T2写的时候加锁,让T1读的时候等待,等T2提交后才允许读,就可以避免脏读现象。

不可重复读是因为事务 T1先读了一条记录,随后事务T2修改了当前记录并提交,等T1再读时发现跟第一次读的不一致了。那我们只要在T1读的时候加锁,让T2写的时候等待,等T1读完之后T2再去进行写操作,就可以避免不可重复读。

幻读是因为事务T1查询了一个范围内的记录,随后事务T2对当前范围内插入了新的记录并提交,导致T1再查询范围时发现记录数变了。那我们可以在T1查询的范围上给加锁,此时T2在此范围内插入数据时让其等待,就可以避免幻读。

三、锁从不同角度的分类

mysql中的锁,不但保证了数据的一致性,而且还为实现各个隔离级别提供了保证。尤其对于一些敏感数据上我们必须采用加锁的方式,所以锁对数据库而言显得尤其重要,也更加复杂。本文从mysq锁的不同角度,详细聊一聊mysql中的锁。

四、操作角度:读写锁

对于数据库中并发事务的读-读不会引起什么问题。对于 写-写读-写写-读这些情况可能会引起一些问题,需要通过 MVCC加锁方式解决。在使用加锁方式时,由于既要允许读-读情况不受影响,又要使 写-写读-写写-读情况中的操作互相阻塞,所以mysql实现一个由两种类型的锁组成的锁系统来解决。这两种类型的锁通常被称为 共享锁(Shared Lock) 和 排他锁(Excluslve Lock),也叫 读锁(read lock)和 写锁(write lock) 。

4.1 共享锁

也称为读锁,英文用 S表示。针对同一份数据,多个事务的共享锁可以同时进行而不互相影响,互相不阻塞。

4.2 排他锁

也成为写锁,英文用 X表示。此事务没有完成前,它会阻断其他的排他锁和共享锁。这样能确保在给定的时间里,有且只有一个事务能访问同一资源。

4.3 读锁案例

  • 对读的记录加S锁

一般情况下,我们需要对操作加S锁,以避免不可重复读幻读这些问题。

select …… lock in share moe;
# 或
select …… for share; #(8.0语法)

在普通的select语句后面加 lock in share mode,如果当前事务执行了该语句,那么它会为读取到的记录加S锁,此时允许其他事务继续获取这些记录的S锁,但是不能获取这些记录的X锁。想获取X锁的事务将会阻塞,知道当前事务的S锁释放掉后才可以。

读-读

读-写

4.4 写锁案例

  • 对读取记录加X锁

在有些场景下,比如涉及到金额存取款问题等,我们需要对读操作加X锁。即当前事务在读取的时候,不需要其他的事务进行读写操作。

select …… for update;

在普通的select语句后加for update,如果当前事务执行了该语句,那么事务会为读取的记录加X锁。此时其他事物,无论是对这些记录加S锁 还是 X锁,都会进入阻塞状态。

写-读

写-写

4.5 小结:

当一个事务加了S锁,其他事务S锁不影响,X锁阻塞。

当一个事务加了X锁,其他事务S锁阻塞,X锁阻塞。

S锁 X锁
S锁 不阻塞 阻塞
X锁 阻塞 阻塞

在5.7及之前版本,select …… for update,如果获取不到锁,会一直等待,直到innodb_lock_wait_timeout超时。
在8.0版本中,select …… for update,select …… for share 添加 NOWAITSKIP LOCKED语法,可以跳过锁等待,或者跳过锁定。

如果查询的行已经加锁:

  • NOWAIT:会立即返回报错。
  • SKIP LOCKED:会立即返回结果,结果中不包含被锁定的行。

五、 数据操作粒度角度:表锁、页锁、行锁

为了尽可能提高数据库的并发度,每次锁定的数据范围越小越好,理论上每次只锁定当前操作的数据会得到最大的并发度,但是管理锁是很耗资源的事情(涉及获取、检查、释放锁等动作)。因此数据库系统需要在高并发响应系统性能两方面进行平衡,就产生了 锁粒度的概念。

对一条记录加锁影响的就是该记录而已,我们就说这个锁的粒度比较细;一个事务也可以在表级别进行加锁,我们称之为 表锁,对一个表加锁会影响这个表的记录,我们就说这个锁的粒度比较粗。锁的粒度主要分为表锁、页锁和行锁。

5.1 表锁

5.1.1 表级别的读写锁

在对表执行select、insert、delete、update 这些DML语句时,InnoDB不会为该表添加 S锁X锁的,但是其他事务对该表进行 alter table、drop table 等这类 DDL语句时会发生阻塞。同理,当事务对表进行 DDL时,其他事务的 DML也会进行堵塞。这个过程是通过在server层使用一种称之为元数据锁(Metadata Locks,简称 MDL)结构来实现的。

手动获取表 的 S锁或者X锁

  • lock tables t read:对表 tS锁
  • lock tables t write:对表 tX锁
  • lock tables t1 read, t2 write;:对表t1S锁t2加写锁。

查看正在加锁的表:

  • show open tables where In_use > 0;

释放当前会话的读写锁:

  • unlock tables:只能释放当前会话的锁,其他会话的锁释放不了。

小结

关于表锁的读写类型,可以用下面表格来概述:

锁类型 自己可读 自己可写 自己可操作其他表 他人可读 他人可写
读锁 否,等
写锁 否,等 否,等

一般情况下不会对InnoDB存储引擎使用表级别的 S锁X锁,它们并不会提供什么额外的保护,只会降低并发能力而已。InnoDB的厉害之处是实现了更细粒度的 行锁

5.1.2 表级别的意向锁

概念

意向锁是由存储引擎自己维护的一种表级锁,我们自己无法手动操作意向锁。当我们给表中的某些记录添加了 共享锁时,存储引擎会自动给所在的表添加 意向共享锁;当我们给表中的某些记录添加了排他锁时,存储引擎会自动给所在的表添加意向排他锁

  • 意向共享锁(intention shared lock,IS):由事务添加行的共享锁时,存储引擎自动给表添加的。
  • 意向排他锁(intention exclusive lock,IX):由事务添加行的排他锁时,存储引擎自动给表添加的。

为什么需要意向锁

此时可能会有疑问,我们既然给表中的记录填加行级的共享/排他锁,为什么还需要给表添加意向锁?其实意向锁的存在,是为了协调行锁和表锁的关系。举个例子:

假如事务T1想给a表添加表的排他锁(X锁),因为排他锁互斥的关系,T1需要在加锁前,判断该表中的所有记录行,是否存在 S锁X锁,如果数据量很大,每一行都去做判断则非常的耗时。所以我们在给表中记录添加S/X锁时,会对应的给表也添加上IS/IX锁。此时事务T1再想给表a添加X锁时,只需要先判断该表是否存在 IS/IX锁即可,就不需要再去遍历每一行判断了,可以提升系统效率。

意向锁之间的关系

行级锁的某一条记录,同一时间内可以存在多个S锁,但只能存在一个X锁,且S锁X锁互相排斥。而在意向锁中,由于多个事务可以给记录同时添加S锁,所以一个表也会存在多个IS锁;由于多个事务可以给表中不同的记录分别添加X锁,所以一个表也会存在多个IX锁。

所以我们得出结论,意向锁之间互不排斥,可以共存。意向锁与行锁之间不排斥,可以共存。

表锁与意向锁之间:表的S锁IS锁可以共存,其余的表锁与意向锁互斥。

小结

  1. InnoDB支持多粒度锁,行级锁可以与表级锁共存。
  2. 意向锁之间互相兼容,意向锁与行级锁之间互相兼容。
  3. 意向共享锁与表共享锁兼容,其余的意向锁与表锁互不兼容。
  4. 意向锁在保证并发的前提下,实现了行锁和表锁共存满足事务隔离性的要求。

5.1.3 表级别的元数据锁

mysql5.5 引入了 meta data lock,简称MDL锁,属于表锁范畴。MDL的作用是,保证读写的正确性。比如如果一个查询正在遍历表中的数据,而执行期间另一个线程对这个表结构做变更,增加了一个字段,那么查询线程拿到的结果跟表结构对不上,肯定不允许的。

因此,当对一个表做增删改查操作的时候,加MDL读锁;当对表做结构变更操作的时候,加MDL写锁。

读锁之间不互斥,因此可以有多个线程同时对一张表增删改查。读写锁之间、写锁之间是互斥的,用来保证变更表结构操作的安全性,解决了DML和DDL操作之间的一致性问题。不需要显示调用,在访问一个表的时候会自动加上。

此时返现DDL操作的事务处于等待状态,看一下当前正在运行的线程,发现该事务正在进行元数据锁等待。

5.2 InnoDB行锁

行锁(Row Lock)也称为记录锁,顾名思义,就是锁住某一行(某条记录)。需要注意的是,mysql 服务层并没有实现行锁机制,行级锁只在存储引擎层实现。

优点:锁定粒度小,发生 锁冲突概率低,可以实现的 并发度搞

缺点:对于锁的开销比较大,加锁会比较慢,容易出现死锁情况。

InnoDB与MyISAM最大不同有两点:一是支持事务;二是采用了行级锁。

5.2.1 记录锁

记录锁是有S锁和X锁之分的,称之为S型记录锁X型记录锁

  • 当一个事务获取了一条记录的S型记录锁后,其他事务也可以继续获取该记录的S型记录锁,但不可以继续获取X型记录锁。
  • 当一个事务获取了一条记录的X型记录锁后,其他事务既不可以获取改获取的S型记录锁,也不可以继续获取X型记录锁。

5.2.2 间隙锁

间隙锁可以解决mysql中幻读问题。由于间隙锁细节比较多,比如聚簇索引与二级索引的间隙锁表现不同,二级索引中覆盖索引与回表的表现又不同。所以单独拿出一盘文章来详细聊聊,此处不再介绍。

5.2.3 临键锁

临键锁可以看做是间隙锁和记录锁的结合,也跟间隙锁放在同一篇文章里聊。

5.2.4 插入意向锁

5.3 页锁

页锁就是在页的粒度上进行锁定,锁定的数据资源比行锁要多,因为一个页中可以有多个行记录。当我们使用页锁的时候,会出现数据浪费的现象,但这样的浪费最多也就是一个页上的数据行。页锁的开销介于表锁和行锁之间,会出现死锁。锁定的粒度介于表锁和行锁之间,并发度一般。

每个层级的锁数量是有限制的,因为锁会占用内存空间,锁空间的大小是有限的。当某个层级的锁数量超过了这个层级的阈值时,就会进行锁升级。锁升级就是用更大粒度的锁替代多个更小粒度额锁,比如InnoDB中行锁升级为表锁,这样做的好处是占用的锁空间降低了,但同时数据的并发度也下降了。

六、 悲观锁和乐观锁

从对待锁的态度来看锁的话,可以将锁分成乐观锁悲观锁,从名字中也可以看出这两种锁是两种看待数据并发的思维方式。需要注意的是,乐观锁和悲观锁并不是锁,而是锁的设计思想。

6.1 悲观锁

顾名思义,就是以悲观的态度去看待事务访问。所以为了自己的事务不被其他事务干扰,每次访问数据时都会加锁,这样其他事务想访问数据就会阻塞。悲观锁是一种思想,会通过数据库自身的锁机制来实现,从而保证数据操作的排他性。

在一些商场业务系统中,购买商品的业务可以简化为 查询商品库存-下订单-扣减库存。我们应该保证这三步是原子性操作,如果不加锁,可能最后会出现商品库存是负数的情况。而我们需要将执行的sql语句都放在一个事务中,否则达不到原子性的目的。

# 1. 查询商品库存
select quantity from items where id = 1001 for update ;
# 2. 如果库存大于0,则需要生成订单
insert into orders (……) values (……) :
# 3. 修改商品的库存,num表示购买的数量
update items set quantity = quantity - num where id = 1001;

select …… for update 是mysql中的悲观锁。此时在items表中,if为1001的商品已经被锁定了,如果其他事务要对这个商品进行购买时,必须等待本次事务提交之后才能执行。这样就可以保证当前的数据不会被其他事务修改。

注意:select …… for update 语句执行过程中所有扫描的行都会被锁上,因此在mysql中用悲观锁,必须确定使用了索引而不是全表扫描,否则将会被这个表锁上。

小结:悲观锁不使用的场景较多,它存在一些不足,因为悲观锁大多数情况下依靠数据库的锁机制来实现,以保证程序的并发访问行,这样对数据库性能开销影响很大,特别是长事务而言,这样的开销往往无法承受,这时候就需要乐观锁。

6.2 乐观锁

乐观锁对并发事务持乐观的态度,不在乎其他事务是否修改了数据,所以乐观锁不采用数据库自身的锁机制,而是通过程序来实现的。乐观锁可以用 版本号时间戳机制来实现。

1. 乐观锁的版本号机制

在数据表中设计一个版本字段 version,在读数据时也要把 version 字段的值查出来。然后对数据进行修改的时候,执行 update …… set version = version + 1 where version = version。此时如果有其他事务对这条数据进行了更改,则 where 条件不成立,所以本次修改就不会成功。

这种方式类似于 SVN、GIT版本管理系统,当我们修改了代码进行提交时,首先会检查当前版本号与服务器上的版本号是否一致,如果一直就可以直接提交,如果不一致就需要更新服务器上的最新代码,然后再进行提交。

2. 乐观锁的时间戳机制

时间戳和版本号机制一样,也是在更新提交的时候,将当前库里数据的时间戳和之前查出来的时间戳做比较,如果两者一致,则没有被其他事务更改过,可以更新成功,否则就更新失败。

用乐观锁实现商城业务购买:

# 1. 查询商品库存
select quantity, version from items where id = 1001 ;
# 2. 如果库存大于0,则需要生成订单
insert into orders (……) values (……) :
# 3. 修改商品的库存,num表示购买的数量
update items
set quantity = quantity - num, version = version + 1
where id = 1001 and version = #{version} ;

这里我们也可以根据具体业务,因为 库存不能有小于0的场景,所以还可以加一个 where quantity - num >= 0 的条件。

注意:如果数据库采用了读写分离,当 master 表中写入的数据没有及时同步到 slave 表中的时候,会造成更新一直无效的问题,此时需要强制读取master表的数据(即把select语句放到事务中即可,这时候查询的就是master表)。

6.3 两种锁的使用场景

1、乐观锁适合 读操作多的场景,相对来说写的操作比较少。优点在于 基于程序实现不存在死锁问题,适用场景也会相对乐观,因为它阻止不了除了程序以外的数据库操作。

2、悲观锁适合写操作多的场景,因为写的操作具有排他性。采用悲观锁的方式,可以在数据层面阻止其他事务对该数据的操作权限,防止 读写写写的冲突。

七、 显式锁和隐式锁

7.1 显示锁

通过特点的语句进行加锁,我们一般称之为显示加锁,例如:

显示加共享锁:

select …… lock in share mode

显示加排他锁:

select …… for update

7.2 隐式锁

在聊隐式锁之前,我们先回顾一下记录的行格式。在 InnoDB索引数据结构 一文中,提到过行格式的示意图。

其他信息中存在着该记录的一些隐藏信息,我们称之为 隐藏列。隐藏列包含以下三部分:

  • row_id: 行ID,记录的唯一标识;当用户在表中定义了主键字段就优先选择用户定义的主键,如果没有,就查找是否有定义不为null的唯一索引,如果有就把该列作为主键,如果没有MySQL就会生成一列row_id隐藏列作为主键。
  • trx_id: 事务的ID;记录最后一次操作该数据的事务ID。
  • roll_pointer: 回滚指针,指向的是该记录的上一个版本号,MySQL的MVCC主要就是通过这个字段来实现的。

一个事务在执行insert操作时,如果即将插入的间隙已经被其他事务加了 gap锁,那么本次 insert操作会阻塞,并且当前事务会在该间隙上加一个 插入意向锁,否则一般情况下 insert操作是不加锁的。那如果一个事务T1首先插入了一条记录,在未提交事务之前,其他的事务·T2·:

  • 立即使用 S锁读取这条记录,如果允许,就会产生脏读问题。
  • 立即修改这条记录,也就是给这条记录添加X锁,如果允许,就会产生脏写问题。

这时候上面提到过的 事务id就起作用了。事务T1 在进行 insert操作,这条记录的 trx_id就是 该T1事务的id,此时T2想对该记录添加S/X锁时,首先会看一下该记录的trx_id代表的事务T1 是否处于活跃状态,如果T1处于活跃状态,那么T2就会帮T1创建一个X锁,且锁的 is_waiting属性是false,然后T2进入等待状态(也就是给自己再添加一个锁机构,is_waiting属性是 true)。

即:一个事务新插入记录时,不会产生锁结构,但是由于事务id的存在,相当于加了一个 隐式锁。其他事务在对这条记录加锁的时候,由于隐式锁的存在,会先帮助当前事务生成一个锁结构,然后自己再生成一个锁结构并进入等待状态。 所以 隐式锁是一种延迟加载的机制,这样的目的是为了减少加锁的数量。

隐式锁在实际内存对象中并不含有这个锁信息,只有当产生锁等待是,隐式锁才会转换为显式锁。

隐式锁的逻辑过程

A. InnoDB的每条记录中都有一个隐含的trx_id字段,这个字段存在于聚簇索引的B+Tree中。

B. 在操作一条记录钱,首先根据记录中的 trx_id 检查该事务是否处于活动中事务(未提交)。如果是活动事务,首先将隐式锁转换为显式锁(就是为该事务添加一个锁)。

C. 检查是否有锁冲突,如果有冲突,创建锁,并设置waiting状态为等待。如果没有冲突则不加锁,跳到步骤 E。

D.等待加锁成功,被唤醒,或者超市。

E. 写数据,并将自己的事务的id 写入行记录的 trx_id 字段

八、 全局锁

全局锁就是对整个数据库实例加锁。当需要让整个库处于只读状态的时候,可以使用这个命令,之后其他线程的以下语句会被阻塞:数据更新语句(增删改查)、数据定义语句(建表、修改表结构等) 和 更新类事务的提交语句。全局锁的典型使用场景是做全库逻辑备份

flush table with read lock

九、 死锁

两个事务都持有对方需要的锁,并且都在等待对方先释放,并且双方都不会释放自己的锁。

9.1 举例

事务1 事务2
start transaction;
update account set money = 100 where id = 1
start transaction;
update account set money = 100 where id = 2
update account set money = 200 where id = 2
update account set money = 100 where id = 1

9.2 产生条件

  1. 两个或以上事务。
  2. 每个事务都已经持有锁并且申请新的锁。
  3. 锁资源同事只能被同一个事务持有或者不兼容。
  4. 事务之间因为持有锁和申请锁导致彼此循环等待。

死锁的关键在于:两个或以上的事务加锁的顺序不一致。

9.3 如何处理

方式一:等待,知道超市(innodb_lock_wait_timeout = 50s)

即两个事务互相等待时,当一个事务等待时间超过设置的阈值时,就将其回滚,另外事务继续进行。这种方法简单有效,在innodb中,参数innodb_lock_wait_timeout用来设置超时时间。

缺点:对于在线服务来说,这个等待时间往往是无法接受的。假如把这个配置值改短,比如0.1s,也不合适,容易影响到普通的锁等待。

方式二: 使用死锁检测进行死锁处理

innodb提供了 wait-for graph算法来主动进行死锁检测,每当加锁请求无法立即满足需要并进入等待时,该算法都会被触发。

这是一种较为主动的死锁检测机制,要求数据库保存锁的信息链表事务等待链表两部分信息。

9.4 如何避免

  • 合理实际索引,使业务sql尽可能通过索引定位更少的行,减少锁竞争。
  • 调整业务逻辑sql执行顺序,避免 update/delete 长时间持有锁的sql 在事务里。
  • 避免大事务,尽量将大事务拆成多个小事务来处理,小事务缩短锁定资源的时间,发生锁冲突的几率也更小。
  • 在并发比较高的系统中,不要显示加锁,特别是在事务里显示加锁。如 select …… for update 语句,如果实在事务里运行了 start transation 或者 设置了 autocommit 等于0,那么就会锁定所有查找到记录。
  • 降低隔离级别。如果业务允许,将隔离级别调低,比如从 RR调整为 RC,可以避免很多因为gap锁造成的死锁。

聊聊MySQL中的锁相关推荐

  1. Mysql中S 锁和 X 锁的区别

    S 锁,英文为 Shared Lock,中文译作共享锁,有时候我们也称之为读锁,即 Read Lock.S 锁之间是共享的,或者说是互不阻塞的. MySQL 中的锁还是蛮多的,在之前的文章中,松哥和大 ...

  2. mysql5.0锁定用户_MySQL系列(五)---总结MySQL中的锁

    MySQL中的锁 目录 概述 MyISAM支持表锁,InnoDB支持表锁和行锁,默认为行锁 表级锁:开销小,加锁快,不会出现死锁.锁定粒度大,发生锁冲突的概率最高,并发量最低 行级锁:开销大,加锁慢, ...

  3. mysql进阶: mysql中的锁(全局锁/表锁/行锁/间隙锁/临键锁/共享锁/排他锁)

    锁在生活中处处可见,门锁,手机锁等等. 锁存在的意义是保护自己的东西不被别人偷走/修改. 在mysql中锁的意义也是一样,是为了保护自己的数据不被别人进行修改,从而导致出现脏读,幻读等问题.在学习锁的 ...

  4. 一文了解 MySQL 中的锁

    1. 数据库并发场景 在高并发场景下,不考虑其他中间件的情况下,数据库会存在以下场景: 读读:不存在任何问题,也不需要并发控制. 读写:有线程安全问题,可能会造成事务隔离性问题,可能遇到脏读,幻读,不 ...

  5. MySQL中的锁机制详细说明

    一.MySQL锁机制起步 锁是计算机用以协调多个进程间并发访问同一共享资源的一种机制.MySQL中为了保证数据访问的一致性与有效性等功能,实现了锁机制,MySQL中的锁是在服务器层或者存储引擎层实现的 ...

  6. 【数据库】MySQL中的锁机制

    MySQL中的锁机制 数据库锁定机制简单来说,就是数据库为了保证数据的一致性,而使各种共享资源在被并发访问变得有序所设计的一种规则. MySQL 数据库由于其自身架构的特点,存在多种数据存储引擎,每种 ...

  7. mysql 高并发写入锁表_使用mysql中的锁解决高并发问题

    阿里云产品通用代金券,最高可领1888分享一波阿里云红包. 阿里云的购买入口 为什么要加锁 多核计算机的出现,计算机实现真正并行计算,可以在同一时刻,执行多个任务.在多线程编程中,因为线程执行顺序不可 ...

  8. MySQL中的锁(表锁、行锁)

    锁是计算机协调多个进程或纯线程并发访问某一资源的机制.在数据库中,除传统的计算资源(CPU.RAM.I/O)的争用以外,数据也是一种供许多用户共享的资源.如何保证数据并发访问的一致性.有效性是所在有数 ...

  9. mysql中的锁的指令_mysql中的锁

    MYSQL不同的存储引擎支持不同的锁的机制 MyISAM 支持表锁,InnoDB支持表锁和行锁 表锁,行锁比较 表锁:开销小,加锁快:不会出现死锁:锁定力度大,发生锁冲突概率高,并发度最低 行锁:开销 ...

最新文章

  1. 盛夏海边,用Python分析青岛哪些景点性价比高
  2. Java:RMI远程调用
  3. 关于滴水的VT调试器
  4. 第一章--第一节:环境搭建
  5. boost::spirit模块实现罗马数字解析器(演示符号表)的测试程序
  6. 微软Build 2016开发者大会--兑换承诺
  7. 定积分算法java_变步长梯形积分算法求解函数定积分
  8. Kotlin入门(5)字符串及其格式化
  9. WordPress博客添加首页、文章页、页面、分类页、标签页的关键字和描述
  10. Cannot forward ... response ... committed
  11. python安装tensorflow失败解决办法_pip安装tensorflow总是失败怎么办?
  12. Web渗透测试实战——(2.1)Metasploit 6.0初步
  13. Java架构师成长之道之计算机组成原理概述篇
  14. android 百度地图的经度纬度问题
  15. python编写一个程序、判断用户输入的数是正数还是负数_编写一个程序,判断用户输入的数是正数还是负数。_学小易找答案...
  16. 阿里云服务器桌面版配置
  17. React Native --props使用之吹气球例子
  18. Windows11安装教程
  19. 钢琴学习:B站:时一:《万能左手伴奏》
  20. jupyter保存py格式

热门文章

  1. 测试小故事26:软件测试的艺术
  2. 极品飞车ol 与服务器连接不稳定,极品飞车ONLINE燃擎封测常见问题FAQ
  3. linux如何查进程、杀进程,重启进程
  4. 大学生职业生涯规划计算机科学与,计算机科学与技术专业大学生职业生涯规划书...
  5. 猪猪猫.CN-WINXPSP2电脑城装机12[标准版]
  6. FlashFXP如何上传自己制作的网页,FlashFXP如何使用
  7. 【Linux Mint 深度学习开发环境搭建】开发软件安装
  8. 深思:一个农村大学生眼中的农村经济(天涯)
  9. python计算器思路_python计算器实现过程
  10. 大数据概念解析:分布式计算与服务器集群