mysql-isolation&lock

2021-06-28  本文已影响0人  甜甜起司猫_

mysql-isolation&lock

事务

事务是指多个数据库操作组成一个逻辑执行单元,满足 ACID 四个条件。

A:原子性,即这些操作要么全部成功,要么全部不成功,不存在中间状态
C:一致性,数据库从一个状态转移到另外一个状态,数据完整性约束不变
I:隔离性,一个事务的执行不会影响另外一个事务
D:指持久性,已提交对数据库的修改,应该永久保留在数据库中(但如果MySQL的事务设置不当,可能出现事务已经提交,但是并没有被持久化

隔离级别

  1. read uncommit未提交读:事务可以读取另外一个事务没有提交的数据。 问题:脏读,不可重复读,幻读
  2. read commit提交读:事务只能读取到另外一个已经提交的事务数据。 问题: 不可重复度,幻读
  3. repeatable read重复读:事务执行过程查询结果都是一致的,innodb 默认级别。 问题: 幻读
  4. seriable 串行化:读写都会相互阻塞 问题:

锁机制

一致性非读定锁

指INNODB存储引擎通过行多版本控制的方式来读取当前执行时间数据库中行的数据。如果读取的行正在执行DELETE或UPDATE操作,这时读取操作不会因此等待行上锁的释放。而是会去读取行的一个快照数据。

快照数据是改行之前版本的数据,通过undo段来完成的,undo端是用来在事务中回滚数据,因此快照数据本身是没有额外的开销。

这是INNODB存储引擎的默认设置下的默认读取方式,即读取不会占用和等待表上的锁。但是在不同事务隔离界别下,读取的方式不同。

快照数据其实就是当前行之前的历史版本,每行记录可能有多个版本,一般称这种技术为行多版本技术。由此带来的并发控制,称之为多版本并发控制。

READ COMMINTED和REPEATABLE READ(默认事务隔离级别)的事务隔离级别下,INNODB存储引擎使用非锁定的一致性读。

  1. READ COMMITED:总是读取被锁定行的最新一份快照数据,理论上来讲是违反了ACID中的I特性
  2. REPEATABLE READ:总是读取事务开始时的行数据版本。

一致性锁定读

在事务隔离级别REPEATABLE READ模式下,SELECT使用一致性非锁定读。但是某些情况下,需要显示地对数据库读取操作进行加锁以保证数据逻辑的一致性。这要求数据库支持加锁语句。

# 对读取的行记录加一个X锁,其他事务不能对已锁定的行加任何锁。
SELECT ... FOR UPDATE

# 对读取的记录加上一个S锁,其他事务可以向被锁定的行加S锁,但是如果加X锁,会被堵塞。
SELECT ... LOCK IN SHARE MODE

此外,这种SELECT语句必须在一个事务中进行执行。务必加上

BEGIN, START TRANSACTION
或者
SET AUTOCOMMIT = 0

行锁的三种算法

  1. Record Lock:单个行记录上的锁,总是会去锁住索引记录,如果没有显示设置索引,会使用隐式的主键来进行锁定。
  2. Gap Lock:间隙锁,锁定一个范围,但不包含记录本身
  3. Next-Key Lock:Record Lock + Gap Lock,锁定一个范围,并且锁定记录本身。

锁问题

脏读

脏数据是指未提交的数据。

脏读指的是在不同的事务下,当前事务可以读到另外事务未提交的数据,简单来说就是可以读到脏数据。

在事务隔离级别READ UNCOMMITTED下才会发生,但是实际生产并不会使用这个级别,但是可以将replication环境中的slave节点设置为这个级别,以提升性能。

幻读

幻读是指在一个事务内多次读取同一数据集合。在这个事务还没有结束时,另外一个事务也访问了该同一数据集合,并做了一些DML操作。因此,在第一个事务中的两次读数据之间,由于第二个事务的修改,那么第一个事务两次读到的数据可能是不一样的。这样就发生了在一个事务内两次读到的数据是不一样的情况,这种情况称为幻读,也叫不可重复读。

在事务级别READ REPEATABLE级别下,采用Next-Key Lock算法,避免了不可重复读的现象。

丢失更新

就是一个事务的更新操作会被另一个事务的更新操作所覆盖,从而导致数据的不一致。

在数据库层面,任何事务隔离界别都会通过加锁,来避免出现丢失更新的情况。一般出现在用户编程时发生。

  1. 事务T1查询一行的数据,放入本地内存,并显示给一个终端用户USER1
  2. 事务T2也查询一行的数据,放入本地内存,并显示给一个终端用户USER2
  3. USER1修改这行数据,更新数据库并提交
  4. USER2修改这行数据,更新数据库并提交

解决方式,是将事务并行操作变成串行的操作。所以要对用户读取的记录上加一个排他X锁即可。

select cash into @cash
form account
where user = pUser FOR UPDATE;

锁机制下innodb和myisam区别

innodb 支持行锁,而MyISAM 只支持表锁,因此innodb支持的并发粒度更细更高

为什么事务提交了但是数据没有保存

和log刷盘有关:关键在于fsync

mysql有个参数innodb_flush_log_at_trx_commit可以控制刷盘的时机:

关联redis的刷盘问题,redis的AOF也有同样问题,redis有三种刷盘策略:always 永远, everysec 每秒, no 不主动。默认情况下everysec,即有一秒钟的数据可能丢失。

参考链接:

  1. https://www.cnblogs.com/BlueMountain-HaggenDazs/p/9558979.html
上一篇下一篇

猜你喜欢

热点阅读