一、事务(笔试面试常考)
1.1 事务概述
- 在MySQL数据库中只有InnoDB和BDB存储引擎支持事务,MyISAM存储引擎不支持事务。默认的存储引擎是InnoDB;
- 事务就是将一组SQL语句放在同一批次内去执行;
- 如果一个SQL语句出错,则该批次内的所有SQL都将被取消执行;
- 事务用来保证数据的完整性、正确性,操作的原子性以及并发访问时数据的隔离性;
- 事务用来管理INSERT、UPDATE、DELETE等DML语句;
- 事务必须手动开启、提交、回滚,也可以进行自动提交事务;
- 事务的作用范围是一个SESSION(会话控制)中,一个SESSION中可以有多个事务。常见的SESSION:JDBC中的一个Connection对象,也就是一个线程;命令行窗口也是一个SESSION;
- 事务有中有安全点,可以理解为将大事务拆分成小事务,回滚时只回滚到对应的安全点,并不是回滚全部回滚数据。
1.2 事物的四大特性(ACID)(重点)
原子性(Atomicity):
- 事务是一个操作最基本单元,其对数据的新增、修改、删除,要么全都执行,要么全都不执行,不会结束在中间某个环节;
- 事务一旦被提交,在事务期间对数据的新增、修改、删除,必须全部执行;
- 事务一旦被回滚,在事务期间对数据的新增、修改、删除,必须全部回退。新增数据,必须删除;修改数据必须恢复;删除数据必须重新回归,就好像这个事务从来没有被执行过一样;
- 在一个SESSION中,也就是一个会话期间,事务既没有提交也没有回滚,当会话结束时,数据并不会发生修改.
隔离性(Isolation):
- 数据库允许多个事务同时对相同的数据进行读取和修改,隔离性可以防止多个事务并发执行时由于交叉执行而导致数据的不一致.如果有两个事务,运行在相同的时间内,执行相同的功能,事务的隔离性将确保每一事务在系统中认为只有该事务在使用系统。这种属性有时称为串行化,为了防止事务操作间的混淆,必须串行化或序列化请求,使得在同一时间仅有一个请求用于同一数据。
持久性(Durable):
- 事务完成之后,它对于数据的修改是永久性的,即使系统出现故障也不会丢失.在事务完成以后,该事务对数据库所作的更改便持久的保存在数据库之中,并不会被回滚。
一致性(Consistent):
- 在事务开始之前和事务结束以后,数据库数据的完整性没有被破坏;
- 这表示写入的数据必须完全符合所有的预设规则,这包含数据的精确度、串联性以及后续数据库可以自发性地完成预定的工作。(比如:A向B转账,不可能A扣了钱,B却没有收到)也就是说:如果事务是并发多个,系统也必须如同串行事务一样操作。其主要特征是保护性和不变性(Preserving an Invariant),以转账案例为例,假设有五个账户,每个账户余额是100元,那么五个账户总额是500元,如果在这个5个账户之间同时发生多个转账,无论并发多少个,比如在A与B账户之间转账5元,在C与D账户之间转账10元,在B与E之间转账15元,五个账户总额也应该还是500元,这就是保护性和不变性。
- 原子性、隔离性、持久性三个特性实现一致性.
1.3 更新与丢失
两个或者多个事务,同时对一个数据进行修改,由于每个事务都不知道其他事务的存在,就会发生丢失更新问题–最后的更新覆盖了由其他事务所做的更新。
更新丢失问题有两类
1.事务A的回滚覆盖了事务B已提交的数据
是错误,必须要避免。MySQL已经解决,不用担心,两个事务同时根据主键id更新数据时,一个事务会获取意向排它锁(IX)、排它锁(X锁)和记录锁(Record Lock),X锁是排他性的,当前事务没有提交或者回滚,其他事务不允许操作当前数据。
2.事务A的提交覆盖了事务B提交的数据
不是错误,需要根据具体业务情况来定。MySQL在默认隔离级别(RR)没有解决第二类更新丢失。
1.4 事务控制语句
-- 查询全局、以及当前会话的事务隔离级别
SELECT @@global.tx_isolation, @@tx_isolation;
-- 0表示禁止自动提交,1表示自动提交事务
SET AUTOCOMMIT= 0;
-- 显式地开启一个事务
START;
-- 提交事务,并使已对数据库进行的所有修改成为永久性的
COMMITT;
-- 回滚会结束用户的事务,并撤销正在进行的所有未提交的修改
ROLLBACK;
-- SAVEPOINT 允许在事务中创建一个保存点,一个事务中可以有多个SAVEPOINT
-- 这对于复杂的大事务非常有帮助,例如批量新增1000万的数据,如果中间某一条失败,需要将1000万数据全部回滚吗;如果业务需求,只能全部回滚;如果不需要,可以设置一些保存点,将发生错误时,回滚到最近的保存点上,而不是回滚所有数据
SAVEPOINT identifier;-- 设定保存点,就像游戏关卡保存一样
-- 删除一个事务的保存点,当没有指定的保存点时,执行该语句会抛出一个异常
RELEASE SAVEPOINT identifier;
-- 把事务回滚到标记的保存点
ROLLBACK TO identifier;
-- 设定事务的隔离级别
SET TRANSACTION ISOLATION LEVEL 隔离级别;
-- GLOBAL,设置全局事务隔离级别;SESSION,设置当前会话的隔离级别
-- 如果GLOBAL和SESSION都不设置,表示修改的事务隔离级别将应用于当前session内的下一个还未开始的事务
案例:
/*A在线买一款价格为500元商品,网上银行转账.
A的银行卡余额为2000,然后给商家B支付500.
商家B一开始的银行卡余额为10000
创建数据库shop和创建表account并插入2条数据
*/
CREATE DATABASE `shop`CHARACTER SET utf8 COLLATE utf8_general_ci;
USE `shop`;
CREATE TABLE `account` (
`id` INT(11) NOT NULL AUTO_INCREMENT,
`name` VARCHAR(32) NOT NULL,
`cash` DECIMAL(9,2) NOT NULL,
PRIMARY KEY (`id`)
) ENGINE=INNODB DEFAULT CHARSET=utf8
INSERT INTO account (`name`,`cash`)
VALUES('A',2000.00),('B',10000.00)
-- 转账实现
SET autocommit = 0; -- 关闭自动提交
START TRANSACTION; -- 开始一个事务,标记事务的起始点
UPDATE account SET cash=cash-500 WHERE `name`='A';
UPDATE account SET cash=cash+500 WHERE `name`='B';
COMMIT; -- 提交事务
# rollback;
SET autocommit = 1; -- 恢复自动提交
1.5 事务的隔离级别(重点)
分类:
- 读未提交(Read uncommitted):脏读/不可重复读/幻读都可能
- 读已提交(Read committed简称RC):脏读不可能,不可重复读/幻读都可能
- 可重复读(Repeatable read简称RR):不可重复读/脏读不可能,幻读可能
- 串行化(Serializable):脏读/不可重复读/幻读都不可能,MySQL中事务隔离级别为串行化(serializable)时会锁表,因此不会出现幻读的情况,这种隔离级别并发性极低,开发中很少会用到。
脏读(Dirty Reads):事务A读取到了事务B已经修改但尚未提交的数据,还在这个数据基础上做了操作。此时,如果B事务回滚,A读取的数据无效,不符合一致性要求;
不可重读(Non-Repeatable Reads):一个事务在读取某些数据后的某个时间,再次读取以前读过的数据,却发现其读出的数据已经发生了改变、或某些记录已经被删除了!这种现象就叫做不可重复读;事务A读取到了事务B已经提交的修改数据,不符合隔离性。
幻读(Phantom Reads):一个事务按相同的查询条件重新读取以前检索过的数据,却发现其他事务插入了满足其查询条件的新数据,这种现象就称为"幻读"。
查看事务隔离级别
- show variables like ‘transaction_isolation’;
- select @@transaction_isolation;
InnoDB存储引擎默认的事务隔离级别是Repeatable read(可重复读),同时通过MVCC + Next-Key Lock可以解决幻读问题。
1.6 事务的隔离级别演示
1.6.1 测试数据
-- UNSIGNED代表无符号数,不能是负数
CREATE TABLE `user`
( `id` int(11) NOT NULL AUTO_INCREMENT,
name varchar(20) DEFAULT NULL,
balance decimal(10,2) unsigned DEFAULT NULL,
PRIMARY KEY (id))
ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
-- 插入数据
INSERT INTO `user` VALUES (1, '张三', 200), (2, '李四', 200);
1.6.2 读未提交,出现脏读
SQL执行流程:脏读违反了一致性,是必须要避免的
1.6.3 读已提交,避免脏读和出现不可重复读
只能够读到其他事务已经提交的事务,但是通过相同的SQL语句,多次读取可能读到的数据不相同。可能是其他事务执行了UPDATE和DELETE语句,出现不可重复读并不是错误,这需要在业务进行判定,业务上是否允许,Oracle数据库默认的隔离级别就是读已提交。
1.6.4 可重复读,可以避免脏读、不可重复读但可能出现幻读
可重复读SQL执行流程:
出现幻读SQL执行流程:MySQL默认事务隔离级别为可重复读
1.6.5 串行化,避免脏读、不可重复读和幻读(开发中很少用到,了解)
关系型数据中的ACID与分布式理论中的CAP中,这两个C有什么区别?
- ACID中的C是一致性,在一个事务中,多次对数据进行操作后,数据仍然保证正确性,并不会凭空增加、减少或者消失;
- CAP中C也是一致性,主要指在分布式系统中,一份数据要在多个服务间进行同步。数据的同步是需要时间,复制数据可能失败,需要保证多个服务间数据的一致性。常见的有强一致性、弱一致性和最终一致性;
- 二者目的不同,因而达到的效果也不同。ACID更强调的是单个数据的正确性、完整性,CAP更强调的是多个服务间数据的一致性。
二、索引
2.1 索引的概述
- 索引本质上是一种排好序的数据结构,是真实存在的,存储到物理磁盘文件中;
- 帮助MySQL快速获取数据,可以将随机IO转变成顺序IO,加快数据的查询速度;
- 对指定的列或者多列添加额外的数据结构,让查找变得更快,可能降低新增、修改、删除的时间;
- 没有特别说明,一般说的索引都是指B树或者B+树;
- 可以理解为书本前面的目录,通过目录快速定位对应的页码,加快查找的过程。如果没有目录就需要从开始遍历数据进行查找。
2.2 索引的优缺点
优点:
- 可以大大提高查询速度;
- 可以显著的减少查询中分组和排序的时间**(减少查询时间)**;
- 可以加速表与表的连接;
- 可以通过创建唯一索引,可以保证每一行数据的唯一性。
缺点:
- 创建索引时,需要对表加锁,在锁表的同时,可能会影响到其他的数据操作;
- 索引需要磁盘的空间进行存储,如果针对单表创建了大量的索引,可能比数据文件更快达到大小上限;
- 当对表中的数据进行新增、修改或者删除时,也会触发索引的维护,而维护索引需要时间,可能会降低数据操作的性能,增加执行时间。
2.3 索引的分类
**主键索引:**使用主键字段的索引就是主键索引,其他都是辅助索引(只有一个);
**辅助索引:**辅助索引以非主键字段生成的称为辅助索引,又称为次级索引,二级索引(可有多个);
**聚簇索引:**只有Innodb存储引擎支持,且使用主键或者非空唯一键或者默认row_id作为索引;
非聚簇索引(非聚集索引):如果表的存储引擎为InnoDB,除了主键或者非空唯一键或者row_id,之外的其他字段,作为索引列都是非聚簇索引,如果表的存储引擎为MyISAM,使用到的索引都为非聚簇索引;
**唯一索引(添加了唯一约束):**一个或者多个字段添加了唯一约束,形成唯一索引;
全文索引:(使用较少)只能用于MyISAM类型的数据表,只能用于CHAR , VARCHAR , TEXT数据列类型,适合大型数据集;
2.4 索引的准则和数据结构:
准则:
- 索引不是越多越好;
- 不要对经常变动的数据加索引;
- 小数据量的表建议不要加索引;
- 索引一般应加在查找条件的字段。
**数据结构:**B树索引(B树和B+树)、Hash索引、R-索引(空间索引)、全文索引(倒排索引,使用较少)。
-- 不同的存储引擎支持的索引类型也不一样 InnoDB 支持事务,支持行级别锁定,支持 B-tree、Full-text 等索引,不支持 Hash 索引; MyISAM 不支持事务,支持表级别锁定,支持 B-tree、Full-text 等索引,不支持 Hash 索引; Memory 不支持事务,支持表级别锁定,支持 B-tree、Hash 等索引,不支持 Full-text 索引; NDB 支持事务,支持行级别锁定,支持 Hash 索引,不支持 B-tree、Full-text 等索引; Archive 不支持事务,支持表级别锁定,不支持 B-tree、Hash、Full-text 等索引;
2.5 索引常见面试题
B树和B+树有什么区别,为什么MySQL使用B+树作为索引底层的数据结构?
MyISAM和InnoDB是如何使用B+树索引的
聚簇索引和非聚簇索引有什么区别