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
进行显示锁定。