知识点目录
- java数据库连接
- 1、数据库的四个事务隔离级别、怎么实现
-
- 什么是事务
- (1)数据库事务的四大特性
- (2)不考虑隔离性可能会发生的问题
- (3)数据库的四种隔离级别
- (4)共享锁和排它锁
- 2、怎么验证mysql的索引是否满足需求
- 3、获取数据库版本
- 4、mysql常用的引擎
-
- (1)区别
- (2)MySQL中的日志log
-
- 1)innoDB如何保证事务的原子性,持久性和一致性
- 2)两阶段提交
- (3)WAL技术
- (4)mysql底层执行过程
- 5、行锁、表锁、记录锁和间隙锁
- 6、悲观锁和乐观锁
- 7、问题排查手段
-
- 8、性能优化
-
- 9、MVCC
-
- (1)InnoDB存储引擎MVCC的实现策略
- (2)读已提交和可重复读都是基于MVCC实现的,有什么区别
- (3)事务操作版本号比较
- (4)解决的问题
- 10、索引
-
- (1)什么是索引
- (2)innoDB索引实现
- (3)主键索引和非主键索引的区别
- (4)简述聚集索引和稀疏索引
- (5)简述主键索引和唯一索引
- (6)其他类型索引
- (7)简述回表查询
- 11、哈希索引和自适应哈希索引
- 12、索引的使用场景,为什么使用索引,哪些不适合使用索引
-
- (1)索引的使用场景
- (2)哪些不适合使用索引
- (3)何时索引会失效
- 13、介绍B+树
- 14、为什么使用B+树作为索引而不是哈希表
- 15、简述MySQL主从复制
-
- 16、mysql为什么采用自增id作为主键
- 17、大量数据的分页查询怎么优化
- 18、分库分表怎么做
- 19、分布式事务解决方案
- 20、缓存穿透、缓存击穿和缓存雪崩
- 21、数据库基本类型
-
- 22、数据库三大范式
- 23、SQL语句
java数据库连接
Class.forName("com.mysql.cj.jdbc.Driver");
Connection conn = DriverManager.getConnection(url, user, password);
1、数据库的四个事务隔离级别、怎么实现
什么是事务
数据库事务( transaction)是访问并可能操作各种数据项的一个数据库操作序列,这些操作要么全部执行,要么全部不执行,是一个不可分割的工作单位。事务由事务开始与事务结束之间执行的全部数据库操作组成。
(1)数据库事务的四大特性
- Atomicity(原子性):一个事务中的所有操作,或者全部完成,或者全部不完成,不会结束在中间某个环节。事务在执行过程中发生错误,会被恢复到事务开始前的状态。
- Consistency(一致性):一致性是指事务必须使数据库从一个一致性状态变换到另一个一致性状态,也就是说一个事务执行之前和执行之后都必须处于一致性状态。
- Isolation(隔离性):数据库允许多个并发事务同时对其数据进行读写和修改,隔离性可以防止多个事务并发执行时由于交叉执行而导致数据的不一致。
- Durability(持久性):事务处理结束后,对数据的修改就是永久的,即便系统故障也不会丢失。
(2)不考虑隔离性可能会发生的问题
- 脏读:脏读是指在一个事务处理过程里读取了另一个未提交的事务中的数据。当一个事务正在多次修改某个数据,而在这个事务中这多次的修改都还未提交,这时一个并发的事务来访问该数据,就会造成两个事务得到的数据不一致。
- 不可重复读:不可重复读是指在对数据库中的某个数据,一个事务范围内多次查询却返回了不同的数据值,这是由于在查询间隔,被另一个事务修改并提交了。
- 幻读:幻读是事务非独立执行时发生的一种现象。例如事务T1对一个表中所有的行的某个数据项做了从“1”修改为“2”的操作,这时事务T2又对这个表中插入了一行数据项,而这个数据项的数值还是为“1”并且提交给数据库。而操作事务T1的用户如果再查看刚刚修改的数据,会发现还有一行没有修改,其实这行是从事务T2中添加的,这就是发生了幻读。可以使用间隙锁解决
- 更新丢失:当一个事务进行时,另一个事务在上一个事务提交之前修改了相同行的数据,然后上一个事务提交的时候会覆盖这个事务的修改。
(3)数据库的四种隔离级别
- Serializable(串行化):提供严格的事务隔离。要求失去序列化执行,事务只能一个接一个地执行,不能并发执行。仅仅通过“行级锁”是无法实现事务序列化的,必须通过其他机制保证新插入的数据不会被刚执行查询操作的事务访问到。
- Repeatable read(可重复读):处理更新丢失、脏读和不可重复读取。读取数据的事务将会禁止写事务,但允许读事务,写事务则禁止任何其他事务。可通过“共享读锁”和“排他写锁”实现。
- Read committed(读已提交):处理更新丢失、脏读。读取数据的事务允许其他事务继续访问该行数据,但是未提交的写事务将会禁止其他事务访问该行。可通过“瞬间共享读锁”和“排他写锁”实现。
- Read uncommitted(读未提交):只处理更新丢失。如果一个事务已经开始写数据,则不允许其他事务同时进行写操作,但允许其他事务读此行数据。可通过“排他写锁”实现。
(4)共享锁和排它锁
共享锁也称为读锁,相互不阻塞,多个客户在同一时刻可以同时读取同一个资源而不相互干扰。排他锁也称为写锁,会阻塞其他的写锁和读锁,确保在给定时间内只有一个用户能执行写入并防止其他用户读取正在写入的同一资源。
2、怎么验证mysql的索引是否满足需求
Explain select * from table where type=1
3、获取数据库版本
Select version()
4、mysql常用的引擎
- MyIASM引擎:MyISAM不支持事务,Myisam支持表级锁,不支持行级锁,表不支持外键,该存储引擎存有表的行数,count运算会更快。适合查询频繁,不适合对于增删改要求高的情况。索引和数据放在不同的文件下。
- InnoDB引擎:InnoDB 是 MySQL 的默认事务型引擎,支持事务,表是基于聚簇索引建立的。支持表级锁和行级锁,支持外键,适合数据增删改查都频繁的情况。MySQL运行时,innoDB会在内存中建立缓冲池,用于缓冲数据和索引。由于锁的粒度小,写操作是不会锁定全表的,所以在并发度高的场景下使用会提升效率。采用 MVCC 来支持高并发,并且实现了四个标准的隔离级别。其默认级别是 REPEATABLE READ,并通过间隙锁策略防止幻读,间隙锁使 InnoDB 不仅仅锁定查询涉及的行,还会对索引中的间隙进行锁定防止幻行的插入。索引和数据都放在一个文件里。
MySQL在5.1之前默认MyIASM,在此之后默认为innoDB。都是表级别的。
(1)区别
- innoDB支持事务,myisam不支持
- innoDB支持外键,myisam不支持
- innoDB是聚集索引,数据文件和主键是绑在一起的myisam是非聚集索引,索引和数据文件是分离的,索引保存数据文件的指针
- innoDB不保存表的具体行数
- myisam表格可以被压缩后进行查询
- innoDB支持行级和表级锁,myisam只支持表级锁
- innoDB必须要有唯一索引,没有指定的话会自己生产一个ROW_id来充当默认主键
(2)MySQL中的日志log
- redo log:存储引擎级别的log,关注与事务的恢复,再重启MySQL服务时,根据redo log进行重做,从而使事务有持久性(InnoDB通过redo log保证即使数据库发生异常重启,之前提交的记录都不会丢失,这个能力称为crash-safe)
- undo log:是存储引擎级别的log,保证数据的原子性,该log保存了事务发生前的数据的一个版本,可以用于回滚,是MVCC的重要实现方法之一
- bin log:数据库级别的log,关注恢复数据库的数据
1)innoDB如何保证事务的原子性,持久性和一致性
- 利用undo log保障原子性(innoDB)
- redo log保证事务的持久性(innoDB)
- undo log+redo log保障一致性。
2)两阶段提交
为了保证binlog和redo log两份日志的逻辑一致,最终保证恢复到主备数据库的数据是一致的,采用两阶段提交的机制。
- 执行器调用存储引擎接口,存储引擎将修改更新到内存中后,将修改操作记录redo log中,此时redo log处于prepare状态。
- 存储引擎告知执行器执行完毕,执行器生成这个操作对应的binlog,并把binlog写入磁盘。
- 执行器调用引擎的提交事务接口,引擎把刚刚写入的redo log改成提交commit状态,更新完成。
(3)WAL技术
WAL全称为write-Ahead logging,在事务提交写入磁盘前,会先写到redo log里。如果直接写入磁盘设计磁盘的随机I/O访问,是非常耗时的过程,相比之下先写入log,后面在找合适的时间写入磁盘可以提高性能。
(4)mysql底层执行过程
首先判断sql的查询条件是否是索引字段,如果是索引字段,则走索引查询。MyISAM直接去MYI文件根据b+树遍历查找元素,存储的是元素在表中的行地址,再去MYD文件中找到要查找的数据。
5、行锁、表锁、记录锁和间隙锁
MyISAM只支持表锁,InnoDB支持表锁和行锁,默认为行锁。
- 表锁:开销小,加锁块,不会出现死锁。锁定粒度大,发生锁冲突的概率最高,并发量最低。表锁响应的是非索引字段,即全表扫描
- 行锁:开销大,加锁慢,会出现死锁。锁粒度小,发生锁冲突的概率小,并发度高。行锁是基于索引加载的,所以行锁要加在索引响应的行上。
- 记录锁:必须是精确命中索引且索引是唯一索引,如主键,只会锁定指定的一行。
- 间隙锁:当用范围查询时,查询条件命中索引,并且没有查询到符合条件的记录,就会将查询范围数据进行锁定。
6、悲观锁和乐观锁
- 乐观锁:每次拿数据的时候都认为别人不会修改,所以不会上锁,但是在提交更新的时候会判断一下在此期间别人有没有去更新这个数据。
- 悲观锁:每次去拿数据是都会认为别人会修改,所以每次在拿数据的时候都会上锁,阻止别人那数据,直到这个锁被释放。
数据库的乐观锁需要自己实现,在表里面添加一个 version 字段,每次修改成功值加 1,这样每次修改的时候先对比一下,自己拥有的 version 和数据库现在的 version 是否一致,如果不一致就不修改,这样就实现了乐观锁。
7、问题排查手段
- 使用show processlist命令查看当前所有连接信息
- 使用explain命令查询SQL语句执行计划
- 开启慢查询日志,查看慢查询的SQL
(1)如何解决数据库死锁
- 预先检测到死锁的循环依赖,并立即返回一个错误。
- 当查询的时间达到锁等待超时的设定后放弃锁请求。
8、性能优化
- 优化数据库表结构设计,如字段的数据类型、表的存储引擎等
- SQL优化,如避免使用Select *
- 分表
- 大事务:避免一次处理太多的数据,移除不必要在事务中的select操作
- 数据库参数配置优化,如最大连接数等配置
- 主从复制,读写分离
- 增加缓存层,如使用redis等高速缓存,降低数据库压力
- 升级硬件
(1)MySQL优化流程
- 通过慢日志定位执行较慢的SQL语句
- 根据explain对这些关键字段进行分析
- 根据分析结果进行优化
(2)慢查询
慢查询就是在日志中记录运行比较慢的SQL语句,可以指定时间
9、MVCC
MVCC(Multi-Version Concurrency Control,多版本并发控制),即同一条记录在系统中存在多个版本。其存在目的是在保证数据一致性的前提下提供一种高并发的访问性能。对数据读写在不加读写锁的情况下实现互不干扰,从而实现数据库的隔离性,在事务隔离级别为读提交和可重复读中使用到。
- 基本特征:
- 每行数据都存在一个版本,每次数据更新都更新该版本。
- 修改时复制出当前版本随意修改,各个事务之间无干扰。
- 保存时比较版本号,如果成功,则覆盖原纪录,失败则放弃复制的版本
(1)InnoDB存储引擎MVCC的实现策略
在每一行数据中额外保存两个隐藏的列:当前行创建时的版本号和删除时的版本号(可能为空,其实还有一列称为回滚指针,用于事务回滚,不在本文范畴)。这里的版本号并不是实际的时间值,而是系统版本号。每开始新的事务,系统版本号都会自动递增。事务开始时刻的系统版本号会作为事务的版本号,用来和查询每行记录的版本号进行比较。
在InnoDB中,事务在开始前会向事务系统申请一个事务ID,该ID是按申请顺序严格递增的。每行数据具有多个版本,每次事务更新数据都会生成新的数据版本,而不会直接覆盖旧的数据版本。数据的行结构中包含多个信息字段。其中实现MVCC的主要涉及最近更改该行数据的事务ID(DB_TRX_ID)和可以找到历史数据版本的指针(DB_ROLL_PTR)。InnoDB在每个事务开启瞬间会为其构造一个记录当前已经开启但未提交的事务ID的视图数组。通过比较链表中的事务ID与该行数据的值与对应的DB_TRX_ID,并通过DB_ROLL_PTR找到历史数据的值以及对应的DB_TRX_ID来决定当前版本的数据是否应该被当前事务所见。最终实现在不加锁的情况下保证数据的一致性。
每个事务又有自己的版本号,这样事务内执行CRUD操作时,就通过版本号的比较来达到数据版本控制的目的。
(2)读已提交和可重复读都是基于MVCC实现的,有什么区别
在可重复读级别下,只会在事务开始前创建视图,事务中后续的查询公用一个视图。读已提交级别下每个语句执行前都会创建新的视图。因此对于可重复读,查询只能看到事务创建前就已经提交的数据,而对于读已提交,查询能看到每个语句启动前就已经提交的数据。
(3)事务操作版本号比较
需要满足以下两个条件才能被事务查询出来
- 删除版本号未指定或者大于当前事务版本号,即查询事务开启后确保读取的行未被删除
- 创建版本号小于或者等于当前事务版本号,即记录创建是在当前事务中,或者事务启动之前。
(4)解决的问题
解决脏读,幻读和不可重复读,但不能解决更新丢失问题。
10、索引
(1)什么是索引
- 索引:索引是帮助MySQL高效获取数据的数据结构,在关系型数据库中,索引具体是一种对数据库中一列或多列的值进行排序的存储结构。索引的目的在于提高查询效率;实际上索引也是一张表,该表保存了主键与索引字段,并指向实体表的记录,索引列也是要占用空间的。
(2)innoDB索引实现
- 表数据文件本身就是按照B+树组织的一个索引结构文件
- 聚集索引-叶节点包含了完整的数据记录
- 建innoDB表必须建主键,推荐使用自增主键。(避免往前插入数据,降低维护成本)
- 非主键索引结构的叶子结点存储的是主键值(保证一致性和节省存储空间)
两种数据库引擎的索引实现细节
(3)主键索引和非主键索引的区别
- 主键索引:主键索引索引数据,当查询用的是主键的索引时,只需要扫描主键索引表,然后就可以拿到相应的数据
- 非主键索引:非主键索引指向主键,当用非主键索引查找时,需要先扫描非主键索引表,找到对应的主键值,然后再去扫描主键索引,才能拿到数据,这个过程叫回表
非主键索引不一定会回表,当查询语句的要求字段全部命中索引,不用回表。如select 主键 from 非主键=XX,此时非主键索引叶子节点即可拿到主键信息,不用回表
在InnoDB中主键索引指向数据,非主键索引指向主键值,在MyISAM中,没有什么区别,都是直接索引着数据的地址。
(4)简述聚集索引和稀疏索引
- 聚集索引按每张表的主键构成一棵B+树,数据库中的每个搜索键值都有一个索引记录,每个数据页通过双向链表连接。表数据访问快,但更新代价高。一张表只能有一个聚集索引,因为要按照顺序存储,只能按照一列排序。
- 稀疏索引不会为每个搜索关键字创建索引记录。搜索过程需要,我们首先按索引记录进行操作,并按顺序收缩,直到找到所需的数据为止
(5)简述主键索引和唯一索引
主键就是能够唯一标识表中某一行的属性或属性组,一个表只能有一个主键,但可以有多个候选索引。主键常常与外键构成参照完整性约束,防止出现数据不一致。主键可以保证记录的唯一和主键域非空,数据库管理系统对于主键自动生成唯一索引,所以主键也是一个特殊的索引。
唯一索引是在表上一个或多个字段组合建立的索引。
主键不能为空,唯一索引列允许空值。主键一定是唯一性索引,唯一性索引不一定是主键。
(6)其他类型索引
- 辅助索引:是非聚集索引,叶子结点不包含记录的全部数据,叶子结点的数据存储的是主键值,需要根据主键值去聚集索引查找数据。
- 联合索引:指对表上多个列的关键词进行索引,Mysql会对第一个索引字段数据进行排序,在第一个字段基础上,再对第二个字段排序。(最左匹配原则)对于联合索引的查询,如果精确匹配联合索引的左边连续一列或者多列,则mysql会一直向右匹配直到遇到范围查询(>,<,between,like)就停止匹配。Mysql会对第一个索引字段数据进行排序,在第一个字段基础上,再对第二个字段排序。
- 覆盖索引:指一个索引包含或覆盖了所有需要查询的字段的值,即索引本身存了对应的值
(7)简述回表查询
在InnoDB中主键索引指向数据,非主键索引指向主键值
通过辅助索引查询,先通过书签查到聚集索引,再根据聚集索引查对应的值,需要两次,即回表查询
11、哈希索引和自适应哈希索引
- 哈希索引只使用与等值查找哈希索引对于每一行数据计算一个哈希码,并将所有的哈希码存储在索引中,同时在哈希表中保存指向每个数据行的指针。只有 Memory 引擎显式支持哈希索引。
- InnoDB不支持哈希索引 ,但是有自适应hash索引。Innodb存储引擎会监控对表上二级索引的查找,如果发现某二级索引被频繁访问,会在内存中基于b树在创建一个hash索引
12、索引的使用场景,为什么使用索引,哪些不适合使用索引
(1)索引的使用场景
- 在经常需要搜索的列上,可以加快搜索速度
- 在作为主键的列上,强制该列的唯一性和组织表中数据的排列结构
- 在经常使用的连接的列上,可以加快连接速度
- 在经常需要根据范围进行搜索的列上,因为索引已经排序,指定的范围是连续的(适用于B+树)
- 在经常需要排序的列上,加快排序查询时间(适用于B+树)
- 在经常适用where句子中的列上,可以加快条件的判断
(2)哪些不适合使用索引
- 对于在查询中很少使用或者参考的列不应创建索引。因为列很少使用的情况下创建索引并不能提高查询效率,反而提高了系统的维护成本和空间需求
- 对于那些只有很少数据值的列不应创建索引。由于列的取值很少,在查询的结果中,结果集的数据行占据了表的很大比例。增加索引并不能明显到的加快检索,例如列表中人的性别
- 对于定义为text,image和bit数据类型的列不应创建索引。因为这些列数据量要么相当大,要么取值很少
- 当修改性能远远大于索引性能是,不应创建索引。因为增加索引会降低修改性能,两者是冲突的
(3)何时索引会失效
- 复合索引不满足最左匹配原则
- 查询条件有or
- where查询语句对索引列有数学运算或函数
13、介绍B+树
- B+树的非叶子结点不保存关键字,只进行数据索引,可以放更多的索引
- 所有数据地址必须到叶子结点才能获取到(所以每次数据查询次数一样)
- 叶子节点包含所有的索引字段
- B+树叶子结点关键字从大到小有序排列,左边结尾数据都会保存右边节点开始数据的指针
14、为什么使用B+树作为索引而不是哈希表
在B+树结构的索引中,索引项是按照索引定义里面出现的字段顺序排序的,索引在查找的时候,找到第一个满足条件的人之后,直接向右遍历就可以了,由于索引是有序的,所有满足条件的人都会聚集在一起。而哈希表不支持模糊查询,只能通过遍历全表来寻找数据。索引字段通过哈希映射成哈希码,如果出现很多冲突的话就会形成很长的链表,会导致查找时间增加。
15、简述MySQL主从复制
mysql提供主从复制功能,可以方便的实现数据的多处自动备份,不仅能增加数据库的安全性,还能进行读写分离,提升数据库负载性能。
流程:
- 在事务完成之前,主库在bin log上记录这些改变,完成bin log写入后,主库通知存储引擎提交事务
- 从库将主库的bin log复制到对应的中继日志。从主库的binlog中读取事件,如果已经读到最新了,线程进入睡眠并等待主库产生新的事件。
读写分离
即只在主库上写,在从库上读,减少数据库的压力,提高性能。
16、mysql为什么采用自增id作为主键
直接原因是其存储机制。mysql采用数据页进行数据存储。如果采用自增主键,在原先数据页写满的情况下,MySQL对于新数据,直接开辟新页进行写操作,如果不采用自增主键,为保障索引有序,新数据需插入到合适的位置上,由此针对数据页满的情况下,MySQL需要申请新页,并将一部分之前的数据页挪到新页上,保证按索引有序存储,相对自增主键IO开销更大。
17、大量数据的分页查询怎么优化
定位对应索引id所处的偏移位置,之后进行查询
select * from table where num = 8 limit 100000,1;
变为
select * from table where num = 8 and id >= (
select id from table where num = 8 limit 100000,1
) limit 100;
由于id走了索引,因此速度会有一定的提升
18、分库分表怎么做
对于分库,即将一个数据库拆分为多个库
可以通过水平拆分(按行拆分),或者垂直拆分(按列字段重新拆分多表)的方式,将表进行拆分
一般可以采用中间件sharding-JDBC进行分库分表
19、分布式事务解决方案
两阶段提交:在这个过程中,有两个角色,分别为master和slave 表决阶段:对于所有slave都将本事务能否成功的信息反馈发给master;执行阶段:master根据所有slave的反馈,通知所有slave,步调一致地在所有分支上提交或者回滚;
20、缓存穿透、缓存击穿和缓存雪崩
- 缓存穿透:指缓存和数据库均没有需要查询的数据,攻击者不断发送这种请求,使数据库压力过大
- 缓存击穿:缓存击穿指缓存中没有数据,但数据库中有改数据。一般这种情况指特定数据的缓存时间到期,但由于并发用户访问改数据特别多,因此去数据库取数据,引起数据库访问压力过大
- 缓存雪崩:指缓存中一大批数据到过期时间,而从缓存中删除。但该批数据查询数据量巨大,查询全部走数据库,造成数据库压力过大。
21、数据库基本类型
tinyint
smallint
mediumint
int/integer
bigint
float
double
decimal
date
time
year
datetime
timestamp
char
varchar
tinyblob
tinytext
blob
text
mediumblob
mediumtext
longblob
longtext
char和varchar的区别
CHAR的长度是不可变的,而VARCHAR的长度是可变的。因此CHAR效率高,VARCHAR效率偏低。
22、数据库三大范式
-
第一范式是最基本的范式。如果数据库表中的所有字段值都是不可分解的原子值,就说明该数据库表满足了第一范式。
-
数据库第二范式:关系模式必须满足第一范式,并且所有非主属性都完全依赖于主码。注意,符合第二范式的关系模型可能还存在数据冗余、更新异常等问题。关系模型(学号,姓名,专业编号,专业名称)中,学号->姓名,而专业编号->专业名称,不满足数据库第二范式
-
数据库第三范式:关系模型满足第二范式,所有非主属性对任何候选关键字都不存在传递依赖。即每个属性都跟主键有直接关系而不是间接关系。接着以学生表举例,对于关系模型(学号,姓名,年龄,性别,所在院校,院校地址,院校电话)院校地址,院校电话和学号不存在直接关系,因此不满足第三范式。
23、SQL语句
sql语句使用