本文分享自华为云社区《-事务隔离的实现》,原文作者:技术火炬手。
事实上在数据库引擎的实现中并不能实现完全的事务隔离,比如串行化。这种事务隔离方式虽然是比较理想的隔离措施,但是会对并发性能产生比较大的影响,所以在MySQL中事务的默认隔离级别是REPEATABLEREADS(可重复读),下面我们展开讨论一下MySQL对数据库隔离性的实现。
MySQL事务隔离性的实现
在MySQLInnoDB(下称MySQL)中实现事务的隔离性是通过锁实现的,大家知道在并发场景下我常用的隔离和一致性措施往往是通过锁实现,所以锁也是数据库系统常用的一致性措施。
MySQL锁的分类
我们主要讨论InnoDB锁的实现,但是也有必要简单了解MySQL中其他数据库引擎对锁的实现。整体来说MySQL中可以分为三种锁的类型表锁、行锁、页锁,其中使用表锁的是MyISAM引擎,支持行锁的是InnoDB引擎,同时InnoDB也支持表锁,BDB支持页锁(不是太了解)。
表锁table-levellocking
表级别的锁顾名思义就是加锁的维度是表级别的,是给一个表上锁,这种锁的特点是开销小,加锁快;不会出现死锁;锁定粒度大,发生锁冲突的概率最高,但是并发度也是最低的,表级锁更适合于以查询为主,只有少量按索引条件更新数据的应用。
MySQL表锁的使用
在MySQL中使用表锁比较简单,可以通过LOCKTABLE语句对一张表进行加锁,如下:
#加锁LOCKTABLET_XXXXXXXXX;#解锁UNLOCKTABLES;
加锁和解锁的语法
LOCKTABLEStbl_name[[AS]alias]lock_type[,tbl_name[[AS]alias]lock_type]...lock_type:{READ[LOCAL]
[LOW_PRIORITY]WRITE}UNLOCKTABLES
需要注意的是LOCKTABLE是指当前会话的锁,也就是通过LOCKTABLE显示的为当前会话获取表锁,作用是防止其他会话在需要互斥访问时修改表的数据,会话只能为其自身获取或释放锁。一个会话无法获取另一会话的锁,也不能释放另一会话持有的锁。同时LOCKTABLE不单单可以获取一个表的锁,也可以是一个视图,对于视图锁定,LOCKTABLES将视图中使用的所有基本表添加到要锁定的表集合中,并自动锁定它们。
LOCKTABLES在获取新锁之前,隐式释放当前会话持有的所有表锁
UNLOCKTABLES显式释放当前会话持有的所有表锁
LOCKTABLE语句有两个比较重要的参数lock_type它可以容许你指定加锁的模式,是读锁还是写锁,也就是READLOCK和WRITELOCK。
READ锁
读锁的特点是持有锁的会话可以读取表但不能写入表,多个会话可以同时获取READ该表的锁
WRITE锁
持有锁的会话可以读取和写入表,只有持有锁的会话才能访问该表。在释放锁之前,没有其他会话可以访问它,保持锁定状态时,其他会话对表的锁定请求将阻塞
WRITE锁通常比READ锁具有更高的优先级,以确保尽快处理更新。这意味着,如果一个会话获取了一个READ锁,然后另一个会话请求了一个WRITE锁,则随后的READ锁请求将一直等待,直到请求该WRITE锁的会话已获取并释放了该锁
通过上面对表锁的简单介绍我们引出两个比较重要的信息,就是读锁和写锁,那么答案就浮出水面,在表级别的锁中其实MySQL是通过共享读锁,和排他写锁来实现隔离性的,下面我们减少共享读锁和排他写锁。
共享读锁(TableReadLock)
共享锁又称为读锁,简称S锁,顾名思义,共享锁就是多个事务对于同一数据可以共享一把锁,都能访问到数据,但是只能读不能修改
对MyISAM表的读操作,不会阻塞其他用户对同一表的读请求,但会阻塞对同一表的写请求;也即当一个session给表加读锁,其他session也可以继续读取该表,但所有更新、删除和插入将会阻塞,直到将表解锁。MyISAM引擎在执行select时会自动给相关表加读锁,在执行update、delete和insert时会自动给相关表加写锁
独占写锁(TableWriteLock)
排他锁又称为写锁,简称X锁,顾名思义,排他锁就是不能与其他所并存,如一个事务获取了一个数据行的排他锁,其他事务就不能再获取该行的其他锁,包括共享锁和排他锁,但是获取排他锁的事务是可以对数据就行读取和修改
独占写锁也被称之为排他写锁,MyISAM表的写操作,则会阻塞其他用户对同一表的读和写操作;MyISAM表的读操作与写操作之间,以及写操作之间是串行的。也即当一个session给表加写锁,其他session所有读取、更新、删除和插入将会阻塞,直到将表解锁
共享锁和独占锁的兼容性
行锁Row-levellocking
在MySQL中支持行锁的引擎是InnoDB,所以我们这里我们指的行锁主要是说InnoDB的行锁。
InnoDB锁的实现和Oracle非常类似,提供一致性的非锁定读、行级锁支持。行级锁没有相关额外的开销,并可以同时得到并发性和一致性。
lock与latch
Latch一般称为闩锁(轻量级的锁),因为其要求锁定的时间必须非常短。若持续的时间长,则应用的性能会非常差。在InnoDB中,latch又可以分为mutex(互斥量)和rwlock(读写锁)。其目的是用来保证并发线程操作临界资源的正确性,并且通常没有死锁检测的机制。
Lock的对象是事务,用来锁定的是数据库中的对象,如表、页、行。并且一般lock的对象仅在事务