Fork me on GitHub

数据库引擎

    MySQL中主要有两个引擎MyISAM呵InnoDB,每个引擎有利有弊。

MyISAM

    MyISAM适用于一些大量查询的应用,但对于有大量写功能的应用不是很好。甚至你只需要update一个字段整个表都会被锁起来。而别的进程就算是读操作也不行要等到当前update操作完成之后才能继续进行。另外,MyISAM对于select count(*)这类操作是超级快的。
PS: 为什么呢?

  • MyISAM保存表的总行数,因此count(*)并且无where子句。很快会返回表的总行数。
  • ……, 利用count(column)并且无where子句,并且此column不为null,很快会返回表的总行数。
  • ……, ……, ……, MySQL会对表进行全表或全索引扫描来确定行数。
  • InnoDB查询count(*), count(column(not null)), count(cloumn(may be null))并且无where子句,MySQL会对表进行全表或全索引扫描来确定行数。
  • MyISAM和InnoDB查询count(*), count(cloumn(not null)), count(column(may be null))并且存在where子句,MySQL会对表进行索引扫描(如果列上有索引),速度也比较快。

InnoDB

    InnoDB的趋势会是一个非常复杂的存储引擎,对于一些小的应用会比MyISAM还慢,但是支持”行锁”,所以在写操作比较多的时候会比较优秀。并且,它支持很多的高级应用,例如:事务。
PS: 行锁?
防止更新丢失,并不能单靠数据库事务控制器来解决,需要应用程序对要更新的数据加必要的锁来解决。

数据库是acid属性

  • 原子性:事务是一个原子操作单元,其对数据的修改,要么全都执行,要么全都不执行。
  • 一致性:在事务开始和完成时,数据都必须保持一致状态。这意味着所有相关的数据规则都必须应用于事务的修改,以操持完整性;事务结束时,所有的内部数据结构(如B树索引或双向链表)也都必须是正确的。
  • 隔离性:数据库系统提供一定的隔离机制,保证事务在不受外部并发操作影响的”独立”环境执行。这意味着事务处理过程中的中间状态对外部是不可见的,反之亦然。
  • 持久性:事务完成后,它对于数据的修改是永久性的,即使出现系统故障也能够保持。

事务并发调度的问题

  • 脏读:A事务读取B事务尚未提交的更改数据,并在这个数据基础上操作。如果B事务回滚,那么A事务读到的数据根本不是合法的,称为脏读。在Oracle中,由于有version控制,不会出现脏读。
  • 不可重复读:A事务读取了B事务已经提交的更改(或删除)数据。比如A事务第一次读取数据,然后B事务更改该数据并提交,A事务再次读取数据,两次读取的数据不一样。
  • 幻读:A事务读取了B事务已经提交的新增数据。注意和不可重复读的区别,这里是新增,不可重复读是更改(或删除)。这两种情况对策是不一样的,对于不可重复读,只需要采取行级锁防止该记录数据被更改或删除,然而对于幻读必须加表级锁,防止在这个表中新增一条数据。
  • 第一类丢失更新:A事务撤销时,把已提交的B事务的数据覆盖掉。
  • 第二类丢失更新:A事务提交时,把已提交的B事务的数据覆盖掉。

三级封锁协议

  • 一级封锁协议:事务T中如果对数据R有写操作,必须在这个事务中对R的第一次读操作前对它加X锁,直到事务结束才释放。事务结束包括正常结束和非正常结束。
  • 二级封锁协议:一级封锁协议加上事务T在读取数据R之前必须先对其加S锁,读完后方可释放S锁。
  • 三级封锁协议:一级封锁协议加上事务T在读取数据R之前必须先对其加S锁,直到事务结束才释放。

    可见,三级锁操作一个比一个厉害(满足高级锁一定满足低级锁)。但有个非常致命的地方,一级锁协议就要在第一次读加X锁,直到事务结束。几乎就要在整个事务加写锁了,效率非常低。三级封锁协议只是一个理论上的东西,实际数据库常用另一套方法来解决事务并发问题

隔离性级别

    MySQL用意向锁(另一种机制)来解决事务并发问题,为了区别封锁协议,弄了一个新概念隔离性级别,MySQL一般默认可重复读

隔离级别/读数据一致性及允许的并发副作用 读数据一致性 脏读 不可重复读 幻读
未提交读 最低级别,只能保证不读取物理上损坏的数据
已提交读 语句级
可重复读 事务级
可序列化 最高级别,事务级

可重复读能解决脏读和不可重复读,但不能解决丢失修改

MySQL的行锁和表锁

  • 表级锁:每次操作锁住整张表。开销小,加锁快;不会出现死锁;锁定粒度大,发生锁冲突的概率最高,并发度最低。
  • 行级锁:每次操作锁住一行数据。开销大,加锁慢;会出现死锁;锁定粒度最小,发生锁冲突的概率最低,并发度也最高。
  • 页面锁:开销和加锁时间界于表锁和行锁之间;会出现死锁;锁定粒度界于表锁和行锁之间,并发度一般。

MyISAM的锁

  • 只有表锁,锁又分为读锁和写锁。
  • 没有事务,不用考虑并发问题。
  • 由于锁的粒度太大,所以当该表写并发量较高时,要等待的查询就会很多了。

InnoDB的行锁和表锁

    没有特定的语法。MySQL的行锁是通过索引体现的。
    如果where条件中只用到索引项,则加的是行锁;否则加的是表锁。比如是主键索引,唯一索引和聚簇索引等。如果sql的where是全表扫描的,想加行锁也爱莫能助。
    行锁和表锁对我们编程有什么影响,要在where中尽量只用索引项,否则就会触发表锁。

乐观锁和悲观锁

乐观锁和悲观锁

事务

事务

索引

索引

Your support will encourage me to continue to create!