MySQL 数据库基础
表锁、行锁、页面锁
- 表级锁:每次操作锁住整张表。开销小,加锁快;不会出现死锁;锁定粒度大,发生锁冲突的概率最高,并发度最低;
- 行级锁:每次操作锁住一行数据。开销大,加锁慢;会出现死锁;锁定粒度最小,发生锁冲突的概率最低,并发度也最高;
- 页面锁:开销和加锁时间界于表锁和行锁之间;会出现死锁;锁定粒度界于表锁和行锁之间,并发度一般
乐观锁、悲观锁、自旋锁
- 乐观锁(Optimistic Lock), 顾名思义,就是很乐观,每次去拿数据的时候都认为别人不会修改,所以不会上锁,但是在更新的时候会判断一下在此期间别人有没有去更新这个数据,可以使用版本号等机制。乐观锁适用于多读,发生冲突的概率低的应用类型,这样可以提高吞吐量。
- 悲观锁(Pessimistic Lock), 顾名思义,就是很悲观,每次去拿数据的时候都认为别人会修改,所以每次在拿数据的时候都会上锁,这样别人想拿这个数据就会block直到它拿到锁。悲观锁适用于可靠的持续性连接,诸如C/S应用。对于Web应用的HTTP连接,先天不适用。
-
自旋锁是什么样的
对于互斥锁,如果资源已经被占用,资源申请者只能进入睡眠状态。但是自旋锁不会引起调用者睡眠,如果自旋锁已经被别的执行单元保持,调用者就一直循环在那里看是否该自旋锁的保持者已经释放了锁。
如果等待的时间比较短,适合使用自旋锁
占用大量的CPU资源
事务
事务就是一组原子性的 SQL 查询,或者说一个独立的工作单元。如果数据库引擎能够成功地对数据库应用该组查询的全部语句,那么就执行该组查询。如果其中有任何一条语句因为崩溃或其他原因无法执行,那么所有的语句都不会执行。也就是说,事务内的语句,要么全部执行成功,要么全部执行失败
数据库的 ACID 了解吗?
-
原子性(Atomicity)
一个事务必须被视为一个不可分割的最小工作单元,整个事务中的所有操作要么全部提交成功,要么全部失败回滚。对于一个事务来说,不可能只执行其中的一部分操作,这就会事务的原子性
-
一致性(Consistency)
数据库总是从一个一致性状态转换到另外一个一致性状态。在前面的例子中,一致性确保了,即使在执行第三、第四条语句之间时系统崩溃,支票账户中也不会损失 200 美元,因为事务最终没有提交,所以事务中所做的修改也不会保存到数据库中 -
隔离性(Isolation)
通常来说,一个事务所做的修改在最终提交以前,对其它事务是不可见的。在前面的例子中,当执行完第三条语句、第四条语句还未开始时,此时有另外一个账户汇总程序开始执行,则其看到的支票账户余额并没有被减去 200 美元。 -
持久性(Durability)
一旦事务提交,则其所做的修改将会永远保存到数据库中。即使系统发生崩溃,事务执行的结果也不能丢失。
隔离级别
-
READ UNCOMMIT (未提交读)
在未提交读级别,事务中的修改,即使没有提交,对其他事务也都是可见的。
事务可以读取未提交的数据,这也被称为脏读。
这个级别会导致很多问题,从性能上来说,未提交读不会比其他级别好太多,但却缺乏其他级别的很多好处,除非真的有非常必要的理由,在实际应用中一般很少使用 -
READ COMMIT (提交读)
大多数数据库系统的默认隔离级别都是提交读(但 MySQL 不是)。提交读满足前面提到的隔离性的简单定义:一个事务开始时,只能 “看见” 已经提交的事务所做的修改。换句话说,一个事务从开始直到提交之前,所做的任何修改对其他事务都是不可见的。这个级别有时候也叫做不可重复读,因为两次执行同样的查询,可能会得到不一样的结果 -
REPEATABLE READ (可重复读)
可重复读是 MySQL 的默认事务隔离级别
可重复读解决了脏读的问题。该级别保证了在同一个事务中多次读取同样记录的结果是一致的。但是理论上,可重复读隔离级别还是无法解决另外一个幻读的问题。所谓幻读,指的是当某个事务在读取某个范围内的记录时,另外一个事务又在该范围内插入了新的记录,当之前的事务再次读取该范围的记录时,会产生幻行。InnoDB 和 XtraDB 存储引擎通过多版本并发控制 (MVCC, Multiversion Concurrency Control) 解决了幻读问题 -
SERIALIZABLE (可串行化)
可串行化是最高的隔离级别。它通过强制事务串行执行,避免了前面说的幻读的问题。简单来说,可串行化会在读取的每一行数据上都加锁,所以可能导致大量的超时和锁争用的问题。实际应用中也很少用到这个隔离级别,只有在非常需要确保数据的一致性而且接受没有并发的情况下,才考虑采用该级别
死锁
死锁是指两个或多个事务在同一资源上相互占用,并请求锁定对方占用的资源,从而导致恶性循环的现象。当多个事务试图以不同的顺序锁定资源时,就可能会产生死锁。多个事务同时锁定同一个资源时也会产生死锁
InnoDB 存储引擎
InnoDB 是 MySQL 的默认事务型引擎,也是最重要、使用最广泛的存储引擎。
除非有非常特别的原因需要使用其他的存储引擎,否则应该优先考虑 InnoDB 引擎。
默认级别是 可重复读,并通过间隙锁策略防止幻读的出现
InnoDB 表是基于聚簇索引建立的
InnoDB 数据存储在表空间中,表空间是由 InnoDB 管理的一个黑盒子,由一系列的数据文件组成
InnoDB 使用 B+ 树
MyISAM 存储引擎
MyISAM 不支持事务和行级锁,而且有一个毫无疑问的缺陷就是崩溃后无法完全恢复
MyISAM 对整张表加锁,而不是针对行。读取时会对需要读到的所有表加共享锁,写入时会对表加排他锁