2021 1月面试笔记
mybatis 嵌套查询 结果查询
嵌套查询就是使用association标签将一个实体类装到另一个实体类中,这样想查询多表时候在指定resultMap时就不用具体编写多余的字段对应属性的代码了,
但是嵌套查询的问题是N+1问题,假如整个查询返回的语句条数是N条,在没有嵌套别的表时候只查询sql一次,但是在使用嵌套查询后,包含的表的实体类会自己查询N次,再加上整体查询的一次,为N+1次,这样大大增加了与数据库交互次数,增加了cpu消耗,所以需酌情使用
结果查询就是使用collection定义实体类(需要把字段一并写全)后,使用left join 或其他链接方式来在sql中链接表,就可以实现多表查询
mysql 分页 索引 调优方法 事务隔离级别 Spring中的事务隔离级别
一般情况下,客户端通过传递 pageNo(页码)、pageSize(每页条数)两个参数去分页查询数据库中的数据,在数据量较小(元组百/千级)时使用 MySQL自带的 limit 来解决这个问题:
收到客户端{pageNo:1,pagesize:10}
select * from table limit (pageNo-1)*pageSize, pageSize;
在数据量较小的时候简单的使用 limit 进行数据分页在性能上面不会有明显的缓慢,但是数据量达到了 万级到百万级 sql语句的性能将会影响数据的返回。这时需要利用主键或者唯一索引进行数据分页;
假设主键或者唯一索引为 good_id
收到客户端{pageNo:5,pagesize:10}
select * from table where good_id > (pageNo-1)*pageSize limit pageSize;
–返回good_id为40到50之间的数据
索引就相当于字典中想查询某个汉字根据页码直接去定位,索引能大大增加数据的读取速度,但同时也使得更新表,删除数据,修改数据变慢
数据库调优:
尽量使用join链接代替子查询
合理的建立索引 但避免在索引上进行计算 和 is/not null
添加缓存机制 如memcached apc
在读操作上添加共享锁 在写上添加独享锁
在需要同时进行同时结束的sql上加上事务,让其尽量不产生脏数据。
事务特性:ACID 原子性、隔离性、持久性、一致性
数据库事务隔离级别:
读未提交:在进行读一条数据时,另一个事务正在修改更新这条数据,但是事务没有结束,在读这条数据时候,读的都是另一事务更新后的数据,但是假若另一事务回滚,这边读到的就是无效的数据。这样可能出现(脏读、不可重复读、幻读)
读已提交:在一个事务正在进行,查询某一条数据时,另一个事务在隐式提交更新关于这条数据,然后在那边读到的数据值就不一样,因为它第二次读的是已更新已提交的数据。(不可重复读、幻读)
可重复读:这个和第一条情况一样,在另一事务隐式提交更新数据时,这边不会读到,只会读到第一次读到的数据,不会更改。(幻读)
串行化:只能读读并发,在写数据的时候只能让一个先进行完后,才能开始执行另一个,期间无法读取改数据,这样的隔离性很高,但是性能效率低
spring的事务隔离级别有五个 四个与上面四个一样 多了一个为默认的隔离级别
String常用方法
equals() trim() replace() concat() substring() startsWith() split()
jvm 新生代老年代 GC经典回收方法
jvm中的堆远远大于栈 并且是线程共享的 而栈是线程独享的
类装载的五个步骤:
加载:根据路径查找对应class文件
检查:检查加载的class文件是否正确
准备:给类中的静态静态变量分配内存空间
解析:虚拟机将常量池中的符号引用改为类中分配的内存的地址
初始化:对静态变量及代码块执行初始化操作
怎样判断对象是否可以回收?
引用计数器方法:每个对象都有对应的应用计数器,当有别的对象进行引用的时候,会对其进行+1,引用释放时对应-1,而当计数器为0的时候就可以被回收
可达性分析:从GC Roots向下搜索,经过的路径称为引用链,而当有对象没有引用链时,代表没有被引用,可以被回收。
Java 中都有哪些引用类型?
· 强引用:发生 gc 的时候不会被回收。
· 软引用:有用但不是必须的对象,在发生内存溢出之前会被回收。
· 弱引用:有用但不是必须的对象,在下一次GC时会被回收。
· 虚引用(幽灵引用/幻影引用):无法通过虚引用获得对象,用 PhantomReference 实现虚引用,虚引用的用途是在 gc 时返回一个通知。
说一下 JVM 有哪些垃圾回收算法?
· 标记-清除算法:标记无用对象,然后进行清除回收。缺点:效率不高,无法清除垃圾碎片。
· 标记-整理算法:标记无用对象,让所有存活的对象都向一端移动,然后直接清除掉端边界以外的内存。
·复制算法:按照容量划分二个大小相等的内存区域,当一块用完的时候将活着的对象复制到另一块上,然后再把已使用的内存空间一次 清理掉。缺点:内存使用率不高,只有原来的一半。
·分代算法:根据对象存活周期的不同将内存划分为几块,一般是新生代和老年代,新生代基本采用复制算法,老年代采用标记整理。
hashmap concurrenthashmap 1.7 1.8
1.8主要优化减少了hash冲突,提高哈希表的存取效率,1.7底层数据结构是数组+链表,1.8是数组+链表+红黑树(链表长度大于8时转换为红黑树 时间复杂度从O(n)变成O(logN)提高了效率) 且1.8采用了尾插法,1.7时头插法,这也是1.8不容易出现环形链表的原因,1.8 rehash能保证原链表顺序,1.7不能
扩容的时候 1.7在插入数据前扩容 1.8在插入后扩容
hashmap允许value为null 允许唯一key为null 其是线程不安全的
当hashmap中key想存储object类型 要重写hashCode()和equals()方法。 hashCode方法重写不好会导致严重的hash碰撞
synchronized 与 lock
synchronized与Lock的区别
两者区别:
1.首先synchronized是java内置关键字,在jvm层面,Lock是个java的接口;
2.synchronized无法判断是否获取锁的状态,Lock可以判断是否获取到锁;
3.synchronized会自动释放锁(a 线程执行完同步代码会释放锁 ;b 线程执行过程中发生异常会释放锁),Lock需在finally中手工释放锁(unlock()方法释放锁),否则容易造成线程死锁;
4.用synchronized关键字的两个线程1和线程2,如果当前线程1获得锁,线程2线程等待。如果线程1阻塞,线程2则会一直等待下去,而Lock锁就不一定会等待下去,如果尝试获取不到锁,线程可以不用一直等待就结束了;
5.synchronized的锁可重入、不可中断、非公平,而Lock锁可重入、可判断、可公平(两者皆可)
6.Lock锁适合大量同步的代码的同步问题,synchronized锁适合代码少量的同步问题。
servlet 生命周期
前端 三级联合
关于IO
IO流是先进先出
4个基本的抽象流类型,所有的流都继承这四个。
输入流 输出流
字节流 InputStream outputStream
字符流 Reader Write
字节流是 1Byte=8位 不支持中文
字符流是 2Byte-16位 支持中文
字符流和字节流的使用范围:字节流一般用来处理图像,视频,以及PPT,Word类型的文件。字符流一般用于处理纯文本类型的文件,如TXT文件等,字节流可以用来处理纯文本文件,但是字符流不能用于处理图像视频等非文本类型的文件。
字节流和字符流的区别:
字节流没有缓冲区,是直接输出的,而字符流是输出到缓冲区的。因此在输出时,字节流不调用colse()方法时,信息已经输出了,而字符流只有在调用close()方法关闭缓冲区时,信息才输出。要想字符流在未关闭时输出信息,则需要手动调用flush()方法。
· 读写单位不同:字节流以字节(8bit)为单位,字符流以字符为单位,根据码表映射字符,一次可能读多个字节。
· 处理对象不同:字节流能处理所有类型的数据(如图片、avi等),而字符流只能处理字符类型的数据。
结论:只要是处理纯文本数据,就优先考虑使用字符流。除此之外都使用字节流。
innoDB存储引擎与MyISAM存储引擎的区别在哪
聚簇索引是索引与数据在一块所以叫聚簇索引 而不在一块的就叫非聚簇索引
一张表只能有一个聚簇索引
最左匹配原则:在mysql索引里 几个条件联合查询时 范围索引(a>3)后面的 匹配索引(a=4)不生效 所以应该把范围查询的字段放在最后
哪些情况下需要建立索引?
在频繁的作为where条件查询的字段 建立复合索引
关联的外键字段可以建立索引 这样两张表在联合查询时候会很快
排序字段order by 可以建立索引
分组字段或统计字段(count(),max())可以建立索引
哪些情况不适合建立索引:
频繁更新的字段不适合建立索引
where条件中用不到的字段不适合
表数据可以确定比较少的不适合
数据重复且均匀的字典不适合
参与列计算的不适合建立索引 因为索引会失效
在where后面有or条件适合,只添加一个索引是不行的,必须在or前后的字段都有索引才会生效
复合索引不满足最左原则后面的就会失效
在模糊查询like 查询%开头的语句适合 索引也会直接失效
查询的数据量太大 如果mysql计算出使用全表扫描的速度更快,便不会使用索引
参与列计算的索引也会直接失效 因为计算后列值都改变了 索引回表不了
innodb支持行锁支持事务(有时候升级为表锁) myisam支持表锁 查找快 不支持事务
表锁: 就是把表锁起来 开销小 加锁快 不会出现死锁 锁粒度大 发生锁冲突概率小 并发度低
行锁: 就是把数据行锁起来 开销大 加锁慢 会出现思索 锁粒度小 发生锁冲突概率搞 并发度高
间隙锁:在锁上一个值id为8的记录时候,会锁上id为8向下和向上取整的一条,将其锁上假如数据库有56789 5条,锁上了id为7,那6和8也被锁上
临键锁:记录锁和间隙锁的合成
读锁(s锁):只可以读,但是不能写
写锁(排它锁,x锁):读和写都不可以 在innodb下使用读写锁要先把autocommit设置为0,因为其默认为1,不然不生效
MDL锁(meta data lock)在开启事务后,别的事务无法修改表结构 在开启查询事务后会自动上MDL锁
乐观锁:
悲观锁:
意向锁:在获取其他的锁前上的锁,不让别人修改表结构
索引是行锁 普通索引在修改记录时,也会加上记录锁
update语句会自动上写锁,记录锁,间隙锁
如何避免死锁:
尽量使用小事务,避免使用大事务,要及时提交和回滚事务,避免死锁发生概率
同一个事务尽量做到一次锁定所需要的所有资源,减少死锁发生概率
对于非常容易发生死锁的业务,可以尝试升级锁的力度,可用表锁减少死锁发生
MVCC:
MVCC是多版本中的并发控制,解决了读写冲突,但是它读的是快照
readreview:在一个事务读数据的时候,在事务未关闭时,再次读,读的是快照,数据不会变(因为要遵循可重复读),即使现在数据被别的事务修改了,读的也是快照,也是之前的数据。
undo log:
记录了旧的数据链,在一个事务未提交但是已更改数据时,会形成数据链,而undo log就是保存修改前的数据链与修改的数据链,方便回滚和管理
redo log:
属于物理日志,方便在断电后数据库重启恢复时候被使用,恢复速度远大于逻辑日志
innodb:
默认事务隔离级别为可重复读,通过MVCC控制读写来实现
锁粒度为行级锁,有更高的并发
支持事务,支持外键,物理主旨结构是聚簇
myisam:
不支持事务,不支持外键
支持全文索引,锁粒度为表级锁
在select count(*)时 myisam会比innodb快很多
关于数据库优化:
首先是sql本身,少用子查询,多用左外链接,少用*来查询所有,可以吧要用到的字段全部列出来,少用临时表,在索引方面,能用复合索引概括所有普通索引,就不用散列的普通索引,锁的方面考虑行锁和表锁,事务上尽量使用粒度小的散列事务,不要使用大事务
负载均衡:
当有10000个请求发送到服务器 其中9000个请求是读取数据,1000个请求是修改数据,可以把9000个请求发送到从服务器,1000个修改请求发送到主服务器,保证每个服务器都不会被压垮,因为当主服务器修改后,从服务器会自动检测主服务器是否更改来保持同步
SpringBoot:
思想:约定大于配置
特点:开箱即用,不用代码生成与xml配置,也可以通过更改默认值来满足特定需求
使用spring initial 在idea创建
将maven配置好仓库与阿里云地址 配入idea中
使用springboot下:
将yml或properties文件下的值通过@Value()传入并打印 引入不同的properties
@ResponseBody只返回值,不让其装载到ViewResolver视图解析器里
修改banner为公司图标或自定义图片
修改网页左边的图标 通过修改favicon
添加阿里巴巴的消息转换器进行传值消息转换
通过pom.xml修改dependency中使用exclusion屏蔽自带Tomcat 然后增加jetty使用jetty服务器
启动系统任务进程,在启动springboot后执行
将项目打包成jar包,可以自执行
自定义jdk证书,将http协议改为安全的https协议
通过设置springboot命令行参数或在yml里定义环境,可以通过传参随时切换环境
tips://springboot集合mybatis时,一定要记得把mapper.xml配置文件放到resource下,别放到上面的包里
配置阿里巴巴德鲁伊druid数据源,数据池监控
整合thymeleaf 而不是jsp
整合swagger,方便前后端交代controller中的各项数据
配置springboot的热部署 相当于自动构建项目
通过注解完成spring提供的定时任务,可以在每个时间段执行工作任务
集成Redis,完成对Redis缓存的插入与取值
Redis解决缓存击穿 在service层加synchronized锁 实现double check
shiro:
封装token(令牌),调用并传给subject
shiroConfig负责定义配置,配置拦截哪些路径,哪些基本路径不拦截
Realm负责完成doGetAuthenticationInfo方法与doGetAuthorizationInfo方法,第一个方法用于管理数据的校验,分自定义的情况抛出异常,让controller捕获后进行处理
第二个方法用于给登录的人赋予权限和角色,让进来的人获得实际权限,再通过对controller加权限注解完成各个权限可以使用和访问的方法
通过shiro与thymeleaf结合,可以通过shiro权限给不同角色显示对应的前端内容
整合mybatis-plus中的pagehelper完成分页操作
使用缓存的注解合理管理Service层的各个方法,来帮助数据存到哪个名字的缓存里
线程间如何通信?
1.使用synchronized锁来实现通信,在锁关闭后线程重新开始竞争锁,可以通过优先级或其他方式实现竞争,从而互相通信。
2.使用 volatile 关键字可定义全局变量,在线程进行时改变。
TCP三次握手 序列号是多少位
序列号是seq占4个字节 32位
确认号是ack占4个字节32位
确认是ACK占1个字节 8位
第一次客户主动去connect服务器,发送SVN假设为J,服务器被动打开。
第二次服务器收到SYN后,会重新发送SYN假设为K,附带ACK应答给客户,而ACK=J+1
第三次客户收到SYN=K,ACK=J+1后,回应ACK表示收到了并连接,代表两边可以发送数据了,ACK=K+1
过滤器和拦截器的区别
过滤器(Filter):
依赖servlet容器,在实现上基于函数回调,它几乎可以对所有请求进行过滤,但缺点是只能在容器初始化时候调用一次,一般使用过滤器为了过滤我们获取到的数据,比如底数文字,危险字符等。
拦截器(interceptor):
拦截器配置一般在springMvc中,它依赖于web框架,在是线上是基于Java的反射机制,属于AOP中的运用,在一个方法前后,抛出异常时做的业务逻辑的操作,其优点是可以使用spring的依赖注入进行业务操作,在controller生命周期内可以多次调用,但是缺点是只能对controller请求进行拦截。
jvm调优
JVM调优目标:使用较小的内存占用来获得较高的吞吐量或者较低的延迟
JVM调优工具:调优可以依赖、参考的数据有系统运行日志、堆栈错误信息、gc日志、线程快照、堆转储快照等。
JVM调优方面:一般通过默认配置,在测试时根据系统运行状况、gc日志、内存监控和垃圾收集器来调整,老年代可能内存小引起FullGC,内存太大导致FullGC时间过长。
代码上:
避免使用过大的对象与数组,在过大的数组与对象在新生代没有空间容纳会进入老年代,提前触发FullGC
避免同时加载大量数据,如从数据库或Excel取出大量数据,可以分批读取,然后尽快清空引用。
集合中有对象的引用,在使用完后要尽快清空其中的引用,避免无用对象进入了老年代。
合理的使用软引用,弱应用配合gc
避免长时间等待外部资源(数据库、网络、设备资源)、缩小对象的生命周期,避免进入老年代,不能及时返回结果可适当采用异步处理的方式。
Redis基本数据类型
string、list、set、hash、sort set
怎么判断索引失效
在语句前加explain就可以,在查询到的一系列参数中有索引生效的选项
hashmap默认加载因子为什么是0.75
首先因为hashmap在达到长度时候会扩容,将所有元素rehash放入其中,这是非常耗时的操作,因为hashmap默认长度为16,而临界值是负载因子乘以长度,在默认0.75*16情况下是12,根据使用随机哈希码,节点出现的概率在hash桶中遵循泊松分布,在桶中元素到达8个时,几率已经低到了0.00000006,也就是说在空间和时间成本折中后,使用0.75可以保证在链表长度超过8基本不可能。
Redis哨兵
当我们主服务器垮掉后,需要将一台从服务器手动转换为主服务器,需要人工干预且费事费力,所以就引入了哨兵模式
哨兵可以自动将从服务器转换为主服务器,且在配置多个哨兵时,它们会互相监控
主观下线:一个哨兵主观的认为主服务器不可用
客观下线:多个哨兵都发现主服务器不可使用便进行投票,达到一定票数后将从服务器提升为主服务器
ArrayList扩容
ArrayList默认数组容量为10,扩容因子为1.5倍甚至更大,其扩容不足是将原数组中元素复制到更大的数组当中然后把剩余的元素add进来
hashcode什么情况一样,为什么
一般我们重写了equals方法后一定要重写hashcode方法,因为要保证equals相等的元素hashcode一定相等,而hashcode是通过其String字符串值转换ASCII码后与内存地址结合生成的
IO和NIO
抽象类和接口
抽象类:
有默认的构造方法
使用extends
可以使用public protected default定义
调用速度快
有普通成员变量
可以包含静态方法
接口:
不存在构造方法
使用implements
默认使用public,且不能使用别的
调用速度慢
没有成员变量
不可以包含静态方法

浙公网安备 33010602011771号