事务

  • 通过执行一组sql完成一个目的

    事务ACID属性

  • 原子性(Atomicity) :事务是一个原子操作单元,其对数据的修改,要么全都执行,要么全都不执行。

  • 一致性(Consistent) :在事务开始和完成时,数据都必须保持一致状态。这意味着所有相关的数据规则都必须应用于事务的修改,以保持数据的完整性。
  • 隔离性(Isolation) :数据库系统提供一定的隔离机制,保证事务在不受外部并发操作影响的“独立”环境执行。这意味着事务处理过程中的中间状态对外部是不可见的,反之亦然。
  • 持久性(Durable) :事务完成之后,它对于数据的修改是永久性的,即使出现系统故障也能够保持。

    并发执行下事务会发送的问题

  • 更新丢失(脏写):两个事务同时读取一个初始值,更新时后更新的会覆盖掉前面更新的值

  • 脏读:一个事务正在事务过程中修改了某个数据,数据会处于不一致的状态,另一个事务就会读取被改后数据,读到的数据就会不准确
  • 不可重读:一个事务在读取某些数据后的某个时间,再次读取以前读过的数据,却发现其读出的数据已经发生了改变、或某些记录已经被删除了!这种现象就叫做“不可重复读”。事务A内部的相同查询语句在不同时刻读出的结果不一致,不符合隔离性
  • 幻读:一个事务按相同的查询条件重新读取以前检索过的数据,却发现其他事务插入了满足其查询条件的新数据,这种现象就称为“幻读”。事务A读取到了事务B提交的新增数据,不符合隔离性

    隔离级别与出现问题关系图

  • 隔离级别会解决的并发问题 | 隔离级别,并发问题 | 脏读 | 不可重复读 | 幻读 | | —- | —- | —- | —- | | 读未提交 | 会出现 | 会出现 | 会出现 | | 读已提交 | 不会出现 | 会出现 | 会出现 | | 可重读 | 不会出现 | 不会出现 | 会出现 | | 序列化 | 不会出现 | 不会出现 | 不会出现 |

锁机制

锁分类

  • 从性能上分为乐观锁(mvcc实现)和悲观锁
  • 从对数据库操作的类型分,分为读锁和写锁(都属于悲观锁)
    • 读锁(共享锁,S锁(Shared)):可以同时读取同一份数据,读操作不会影响数据值
    • 写锁(排它锁):同一个数据同时只能一个线程操作,写操作完之后再进行其他操作
  • 从对数据操作的粒度分,分为表锁和行锁

    表锁

  • 操作时锁住整张表,开销小,锁的粒度大,并发量不高,表数据迁移可使用

    行锁

  • 操作时对表中某一行数据加锁,锁开销较大,锁粒度较小,并发量会提高

    执行引擎对锁的实现

  • 对MyISAM表的读操作(加读锁) ,不会阻塞其他进程对同一表的读请求,但会阻塞对同一表的写请求。只有当读锁释放后,才会执行其它进程的写操作。

  • 对MylSAM表的写操作(加写锁) ,会阻塞其他进程对同一表的读和写操作,只有当写锁释放后,才会执行其它进程的读写操作
  • InnoDB与MYISAM的最大不同有两点:
    • InnoDB支持事务(TRANSACTION)
    • InnoDB支持行级锁
  • MyISAM在执行查询语句SELECT前,会自动给涉及的所有表加读锁,在执行update、insert、delete操作会自动给涉及的表加写锁。
  • InnoDB在执行查询语句SELECT时(非串行隔离级别),不会加锁。但是update、insert、delete操作会加行锁。
  • 读锁会阻塞写,但是不会阻塞读。而写锁则会把读和写都阻塞

    间隙锁(Gap Lock)

  • 间隙锁,锁的就是两个值之间的空隙。Mysql默认级别是repeatable-read

  • 间隙锁是在可重复读隔离级别下才会生效。

    临键锁(Next-key Locks

  • 行锁与间隙锁的组合,比如sql条件是id在区间(1,10],那么整个区间就可以成为临键锁

  • 索引行锁会升级为表锁(RR级别会升级为表锁,RC级别不会升级为表锁)
  • 锁主要加在索引上,对非索引字段更新,行锁可能会变表锁
  • InnoDB的行锁是针对索引加的锁,不是针对记录加的锁,并且该索引不能失效。否则都会从行锁升级为表锁
  • MyIsam使用的表级锁
  • InnoDB有行级锁实现,锁开销比表级锁大,但是并发量比较高,并发量较少时MyIsam可能性能更好

    锁优化建议

  • 尽可能让所有数据检索都通过索引来完成,避免无索引行锁升级为表锁

  • 合理设计索引,尽量缩小锁的范围
  • 尽可能减少检索条件范围,避免间隙锁
  • 尽量控制事务大小,减少锁定资源量和时间长度,涉及事务加锁的sql尽量放在事务最后执行
  • 尽可能低级别事务隔离