MySQL并发与事务

并发控制

MySQL 通过锁解决并发问题,一般有两种类型共享锁、排他锁,也叫读锁、写锁。

锁粒度

加锁后就会影响系统的性能,需要在锁的性能损耗和数据安全性之间寻求平衡。

表锁

用户写数据时需要先获得写锁,这会阻碍该表的所有的读写操作,读锁之间互不影响。写锁可以插到锁队列的读锁前面,反之则不行。

行级锁

行级锁可以最大程度的支持并发处理,但这同时增大了锁的开销,MySQL 行级锁是在存储引擎层实现,服务层没有相关设计。

事务

事务的特征:原子性、一致性、隔离性、持久性,即ACID

原子性:一个事务被视为一个不可分割的最小工作单元,整个事务必须全部提交或者全部回滚

一致性:数据库从一个一致性的状态转换到另一个一致性的状态

隔离性:通常情况下,一个事务所做的修改在最终提交前对于其他事务是不可见的

持久性:一旦事务提交,其所做的修改就会永久保存到数据库中

隔离级别

未提交读(READ UNCOMMITTED):事务中的修改即使没有提交对于其他事务也是可见的,事务可以读取未提交的数据,称之为脏读。

提交读(READ COMMITTED):一个事务开始时,只能看见已经提交的事务所做的修改。即一个事务从开始到提交所做的修改对于其他事务是不可见的。也叫不可重复读。

可重复读(REPEATABLE READ):解决了脏读问题,保证了一个事务中多次读取同一个数据结果是一致的,但是无法解决幻读。幻读是指当一个事务在读取某个范围的记录时,另一个事务在这个范围中插入了新的记录,再次读取会产生不同的结果。可重复读是 MySQL 的默认隔离级别。

可串行化(SERIALIZABLE):强制事务串行化,会在读取的每行数据上加锁,避免了幻读。可能会造成大量的锁超时。

隔离级别 脏读可能性 不可重复读可能性 幻读可能性 加锁读
READ UNCOMMITTED YES YES YES NO
READ COMMITTED NO YES YES NO
REPEATABLE READ NO NO YES NO
SERIALIZABLE NO NO NO YES

死锁

死锁指两个或者多个事务在同一资源上相互占用,并请求对方占用的资源,导致恶性循环。多个事务同时锁定同一资源时,也会产生死锁。

InnoDB 存储引擎可以检测死锁的循环依赖并立即返回错误,InnoDB 目前处理死锁的方式是将持有最少行级锁(写锁)的事务进行回滚。

MySQL 中的事务

自动提交(AUTOCOMMIT):MySQL 默认采用自动提交模式,SHOW VARIABLES LIKE 'AUTOCOMMIT'使用命令查看,1 或者 ON 表示启用,0 或者 OFF 表示禁用。在执行 DDL 相关命令时会强制执行 COMMIT 提交当前活动的事务。可以通过 SET SESSION TRANSACTION ISOLATION LEVEL READ COMMITTED 设置事务的隔离级别。

在事务中混合使用存储引擎:事务是由下层存储引擎实现的,所以在同一个事务中使用多个存储引擎是不可靠的。如果混合使用了事务性和非事务性的表,在提交事务时不会有什么问题,但是回滚时非事务性表上的变更无法回退。

隐式锁定和显示锁定:InnoDB 执行的是两阶段锁定协议,在事务执行过程中随时可以锁定,只有当事务提交或者回滚之后锁才回释放,所有的锁在同一时刻释放,是隐式锁定;InnoDB 支持通过特定语句 LOCK TABLES 进行显示锁定。