Bootstrap

浅析MySQL的表锁和行锁机制

众所周知,MySQL的存储引擎有MyISAM和InnoDB,锁粒度分别是表锁和行锁。

后者的出现从某种程度上是弥补前者的不足,比如:MyISAM不支持事务,InnoDB支持事务。表锁虽然开销小,锁表快,但高并发下性能低。行锁虽然开销大,锁表慢,但高并发下相比之下性能更高。事务和行锁都是在确保数据准确的基础上提高并发的处理能力。下面分别进行介绍:

行锁

行锁的劣势:

  • 开销大;
  • 加锁慢;
  • 会出现死锁

行锁的优势:

  • 锁的粒度小,发生锁冲突的概率低;
  • 处理并发的能力强

加锁的方式:

  • 自动加锁:对于UPDATE、DELETE和INSERT语句,InnoDB会自动给涉及数据集加排他锁;
  • 无锁:对于普通SELECT语句,InnoDB不会加任何锁;当然我们也可以显示的加锁:
  • 共享锁:select * from tableName where ... + lock in share more
  • 排他锁:select * from tableName where ... + for update

InnoDB和MyISAM的最大不同点有两个:

  • InnoDB支持事务(transaction);
  • 默认采用行级锁。

加锁可以保证事务的一致性,下面我们来学习一下MySQL的事务知识.

MySQL 事务属性

事务是由一组SQL语句组成的逻辑处理单元,事务具有ACID属性。 原子性(Atomicity):事务是一个原子操作单元。在当时原子是不可分割的最小元素,其对数据的修改,要么全部成功,要么全部都不成功。 一致性(Consistent):事务开始到结束的时间段内,数据都必须保持一致状态。 隔离性(Isolation):数据库系统提供一定的隔离机制,保证事务在不受外部并发操作影响的"独立"环境执行。 持久性(Durable):事务完成后,它对于数据的修改是永久性的,即使出现系统故障也能够保持。

事务常见问题

更新丢失(Lost Update) 原因:当多个事务选择同一行操作,并且都是基于最初选定的值,由于每个事务都不知道其他事务的存在,就会发生更新覆盖的问题。类比github提交冲突。

脏读(Dirty Reads) 原因:事务A读取了事务B已经修改但尚未提交的数据。若事务B回滚数据,事务A的数据存在不一致性的问题。

不可重复读(Non-Repeatable Reads) 原因:事务A第一次读取最初数据,第二次读取事务B已经提交的修改或删除数据。导致两次读取数据不一致。不符合事务的隔离性。

幻读(Phantom Reads) 原因:事务A根据相同条件第二次查询到事务B提交的新增数据,两次数据结果集不一致。不符合事务的隔离性。

幻读和脏读有点类似 脏读是事务B里面修改了数据, 幻读是事务B里面新增了数据。

事务的隔离级别

数据库的事务隔离越严格,并发副作用越小,但付出的代价也就越大。这是因为事务隔离实质上是将事务在一定程度上"串行"进行,这显然与"并发"是矛盾的。根据自己的业务逻辑,权衡能接受的最大副作用。从而平衡了"隔离" 和 "并发"的问题。MySQL默认隔离级别是可重复读。 脏读,不可重复读,幻读,其实都是数据库读一致性问题,必须由数据库提供一定的事务隔离机制来解决。

+------------------------------+---------------------+--------------+-----
;