索引:

针对表的查询速度的优化的一种结构体,如果把表比喻成一本书,那么索引就是书中的目录快速定位数据
索引提高了查询的速度,但是影响了新增和删除的性能
索引只适合快速查询,不适合频繁新增或删除的表

为什么需要索引?

索引能够大幅提升检索速度,如果没有索引很多时候就需要一个一个去找实际上就是全表扫描,这样效率肯定是非常低的,所以才需要索引结构。

索引的分类:

1.主键索引 只要字段是主键,那么默认就是索引
2.唯一索引 值唯一
3.普通索引
4.复合索引(联合索引)
索引的最佳左匹配原则,对于复合索引来说,查询的时候会从左往右匹配
5.覆盖索引:
SQL语句只需要通过索引就能查询出想要的结果,不必通过二级索引查询主键索引再去查询数据

《索引的数据结构B+Tree》

为什么 使用B+Tree?

当记录较多时,采用平衡二叉树就会出现深度较高的情况,这样检索起来O(lgN)的效率较低,而B+树则是多路平衡树,每个节点可以存储多个数据,通过定位以后,如果在叶节点之前没找到,在相应的叶子节点中通过二叉查找,效率较高。

  1. B+Tree(B+树)
    B+树 是 B-Tree的变形

Mysql 使用的 B+Tree作为索引的数据结构。

只在叶子结点带有指向记录的指针。B+树只在叶子结点存储数据,其它非叶子结点可以存储更过孩子(对B-Tree的优化)。
叶子结点通过指针相连。叶子结点里面有从左到右指针,它是一个双向指针,通过这个指针就可以非常方便实现范围查询。

什么是前缀索引?

数据库连接池的作用:

数据库连接是一种关键的有限的昂贵的资源,这一点在多用户的网页应用程序中体现得尤为突出。对数据库连接的管理能显著影响到整个应用程序的伸缩性和健壮性,影响到程序的性能指标。数据库连接池正是针对这个问题提出来的。数据库连接池负责分配、管理和释放数据库连接,它允许应用程序重复使用一个现有的数据库连接,而不是再重新建立一个;释放空闲时间超过最大空闲时间的数据库连接来避免因为没有释放数据库连接而引起的数据库连接遗漏。这项技术能明显提高对数据库操作的性能。

数据库事务:

保证多个sql语句(DML)执行具有一致性,要么都成功,要么都失败具有ACID特性:
A:原子性、事务必须是原子工作单元;对于其数据修改,要么全都执行,要么全都不执行
C:一致性、事务在完成时,必须使所有的数据都保持一致状态。
I:隔离性、 由并发事务所作的修改必须与任何其它并发事务所作的修改隔离。 对应隔离级别—-防止:胀读、幻度、不可重复读
D:持久性 事务完成之后,它对于系统的影响是永久性的。

开启事务:start
提交事务:commit
回滚事务:rollback
如果一个方法中涉及到了多个SQL语句(DML),必须添加事务

《事务的隔离级别》

1、脏读

所谓脏读,就是指事务A读到了事务B还没有提交的数据,比如银行取钱,事务A开启事务,此时切换到事务B,事务B开启事务—>取走100元,此时切换回事务A,事务A读取的肯定是数据库里面的原始数据,因为事务B取走了100块钱,并没有提交,数据库里面的账务余额肯定还是原始余额,这就是脏读。

2、不可重复读

所谓不可重复读,就是指在一个事务里面读取了两次某个数据,读出来的数据不一致。还是以银行取钱为例,事务A开启事务—>查出银行卡余额为1000元,此时切换到事务B事务B开启事务—>事务B取走100元—>提交,数据库里面余额变为900元,此时切换回事务A,事务A再查一次查出账户余额为900元,这样对事务A而言,在同一个事务内两次读取账户余额数据不一致,这就是不可重复读。

3、幻读

所谓幻读,就是指在一个事务里面的操作中发现了未被操作的数据。比如学生信息,事务A开启事务—>修改所有学生当天签到状况为false,此时切换到事务B,事务B开启事务—>事务B插入了一条学生数据,此时切换回事务A,事务A提交的时候发现了一条自己没有修改过的数据,这就是幻读,就好像发生了幻觉一样。幻读出现的前提是并发的事务中有事务发生了插入、删除操作。

《spring如何开启事务》

Spring boot是默认启动事务的,只需要在(service层中添加)类或者方法上添加@Transactional注解即可(很简单呢!)
类上面
方法上

《如果事务不生效 可能有以下原因》

1、首先要看数据库引擎是否支持注解,mysql默认引擎INNODB是支持的,但MYISAM是不支持的;

《MyISAM 和InnoDB 讲解》

  InnoDB和MyISAM是许多人在使用MySQL时最常用的两个表类型,这两个表类型各有优劣,视具体应用而定。基本的差别为:MyISAM类型不支持事务处理等高级处理,而InnoDB类型支持。MyISAM类型的表强调的是性能,其执行数度比InnoDB类型更快,但是不提供事务支持,而InnoDB提供事务支持以及外部键等高级数据库功能。
2、注解只能被应用到public方法上, 其它方法上不会报错,但不生效;3、默认情况下只会对运行期异常(java.lang.RuntimeException及其子类)和 Error 进行回滚;
4、是否进行了异常捕获,如果使用了try—catch,事务是肯定不生效,也就是系统没有接收到异常场景;

关于使用异常捕获,还想事务生效,可以有几种策略解决相关难题:

1)手动回滚,推荐方式
2)在catch里抛出一个runntimeException
3) 将异常写入注解参数里面,也需要抛出来,原理跟方法2一样的,只是重新指定了事务回滚的异常类型

《SpringMVC前端控制器和执行流程》

tomcat启动流程
初始化默认的JspServlet和DefaultServlet
初始化我们配置的前端控制器DispatcherServlet
因为我们在DispatcherServlet中配置了mvc.xml,因此也会启动Spring容器。SPring容器会帮我们创建相应的bean并管理
创建的对象包括Controller层,Service层,Mapper层,Datasource对象,SqlSession对象等

《什么是前端控制器》

前端控制器本质是一个servlet,是SPringMVC提供的所有请求的的统一入口,因为不同请求可能有共同的操作,这时候就需要前端控制器做统一的处理,比如日志记录,权限检查等,然后再将请求分发给各个处理器去处理

《OOM原因和解决方式》

当堆内存(Heap Space)没有足够空间存放新创建的对象时,就会抛出oom异常。

原因:
1 、无法在 Java 堆中分配对象
2 、吞吐量增加
3 、应用程序无意中保存了对象引用,对象无法被 GC 回收
4 、应用程序过度使用 finalizer。finalizer 对象不能被 GC 立刻回收。finalizer 由结束队 列服务的守护线程调用,有时 finalizer 线程的处理能力无法跟上结束队列的增长。
解决:1 使用 -Xmx 增加堆大小
2 、修复应用程序中的内存泄漏

《 GC 开销超过限制》

引起 OOM? 原因:
1.进程 98%的时间在进行垃圾回收,恢复了不到 2%的堆空间,最后连续 5 个(编译时 常量)垃圾回收一直如此。
解决:
增加堆大小
取消 GC 开销限制
修复应用程序中的内存泄漏

《请求数组的大小超过虚拟机限制引起OOM》

分配一个超过堆大小的数组
解决:使用 -xmx增加堆大小。 要么 修复应用程序中分配巨大数组的bug。

分库库表:

为什么要分库分表(设计高并发系统的时候,数据库层面应该如何设计)?
首先要清楚,分库和分表是两回事,是两个独立的概念。分库和分表都是为了防止数据库服务因为同一时间的访问量(增删查改)过大导致宕机而设计的一种应对策略。

为什么要分库:

按一般的经验来说,一个单库最多支持并发量到2000,且最好保持在1000。如果有20000并发量的需求,这时就需要扩容了,可以将一个库的数据拆分到多个库中,访问的时候根据一定条件访问单库,缓解单库的性能压力。

为什么要分表:

分表也是一样的,如果单表的数据量太大,就会影响SQL语句的执行性能。分表就是按照一定的策略将单表的数据拆分到多个表中,查询的时候也按照一定的策略去查询对应的表,这样就将一次查询的数据范围缩小了。比如按照用户id来分表,将一个用户的数据就放在一个表中,crud先通过用户id找到那个表在进行操作就可以了。这样就把每个表的数据量控制在一定范围内,提升SQL语句的执行性能。

分库分表的两个方案
这里说一下两种分库分表的方案和它们的优缺点。
1.按照range来分。比如说按照时间范围来分库分表,每个库表中存放的都是连续时间范围的数据。但是这种方式一般很少用,因为很容易会产生热点问题,大量的流量都打在最新的数据上了。这种方案的优点在于扩容的时候非常简单,比如只要预备好每个月都准备一个库就可以了,到了下一个新的月份自动将数据写入新的库。缺点则是,如果大部分请求都是访问最新的数据,那么在这里,分库分表的设计目的就只是简单的扩容,而不是为了应对高并发了。
2.按照hash分发。按照某个字段的hash值均匀分散,这个较为常用。优点在于可以平均分配每个库表的数据量和请求压力;缺点在于扩容比较麻烦,因为会存在一个数据迁移的过程,即之前的数据需要重新计算hash值并重新分配到不同的库表中。

“一个人最幸福的时刻,就是找对了人。TA会包容你的不足,并爱着你的一切。”
你要去做一个大人,不要回头,不要难过。

数据库集群之主从集群也就是读写分离,也提到了读写分离其实只是分担了访问的压力,但是存储的压力没有解决。
存储的压力说白了就是随着系统的演化,需求的增加,可能表的数量会逐渐增多,比如一段时间上个新功能就得加个表。并且随着用户量的增多类似用户表的行数肯定会增多,订单表的数据肯定会随着时间而增多,当这种数据量达到千万甚至上亿的时候,读写分离就已经满足不了,读写性能下降严重。
也就是一台服务器的资源例如CPU、内存、IO、磁盘等是有限的,所以这时候分库分表就上啦!

分库

分库讲白了就是比如现在你有一个数据库服务器,数据库中有两张表分别是用户表和订单表。如果要分库的话现在你需要买两台机子,搞两个数据库分别放在两台机子上,并且一个数据库放用户表,一个数据库放订单表

表关联多对多怎么处理:

拆分关系:

增加一个表。使之符合范式。
比如做学生选课系统。多个学生选多门课。这是多对多关系。
这样可以写成三个表。
分别为。学生表(学号,姓名)
课程表(课程号,课程名)
选课表(学号,课程号)
通过选课表,将学生和课程联系起来了。