1.Update语句,数据库进行了一个怎么样的锁
答:有索引的时候是行锁,没有索引就是表锁
补充问题:索引用过吗?怎么建索引,索引失效
建索引例子:ALTER TABLE table_name ADD INDEX index_name (column_list);
ALTER TABLE用来创建普通索引、UNIQUE索引或PRIMARY KEY索引。其中table_name表名,index_name索引名,column_list组成索引的列名。
索引失效:
1、使用 != 导致索引失效
2、类型不一致导致的索引失效
3、使用运算符对索引进行计算或者在索引列使用函数导致的索引失效
4、OR引起的索引失效
SELECT * FROM `user` WHERE `name` = '张三' OR height = '175';
不是所有的OR都是使索引失效,如果OR连接的是同一个字段,那么索引不会失效。
5、模糊搜索导致的索引失效
SELECT * FROM `user` WHERE `name` LIKE '%冰';
当 % 放在匹配字段前是不走索引的,放在后面才会走索引。
6、NOT IN、NOT EXISTS导致索引失效
2. 什么是BIO、NIO、AIO?
答:BIO是传统的同步阻塞式的I/O。NIO是同步非阻塞式IO程序。AIO是异步非阻塞式IO程序
3.Spring中bean的生命周期?
答: Bean作为一个Java对象,具有一定的生命周期。它的生命周期包括以下几个阶段:
实例化:在Java应用程序中,Bean对象是通过new关键字或者反射机制来实例化的。在这个阶段,Bean对象被创建,并分配了内存空间。
设置属性(Bean注入和装配)
初始化:当Bean对象被创建后,需要进行初始化,包括设置属性值、执行一些初始化操作等。在Spring框架中,Bean的初始化可以通过配置文件中的init-method属性进行指定。
使用:在Bean初始化之后,它就可以被应用程序使用了。在使用过程中,Bean可能会调用其他对象的方法,从而导致其他Bean对象被实例化和初始化。
销毁:当Bean对象不再被使用时,应该将其销毁并释放占用的内存空间。在Spring框架中,Bean的销毁可以通过配置文件中的destroy-method属性进行指定。
4.Spring的启动流程
答:
1.首先从main找到run()方法,在执行run()方法之前new一个SpringApplication对象
2.进入run()方法,创建应用监听器SpringApplicationRunListeners开始监听
3.然后加载SpringBoot配置环境(ConfigurableEnvironment),然后把配置环境(Environment)加入监听对象中
4.然后加载应用上下文(ConfigurableApplicationContext),当做run方法的返回对象
5.最后创建Spring容器,refreshContext(context),实现starter自动化配置和bean的实例化等工作。
5:事务什么情况下失效?事务的传播行为
答:
5.1事务传播行为:
//如果有事务, 那么加入事务, 没有的话新建一个(默认)
@Transactional(propagation=Propagation.REQUIRED)
//容器不为这个方法开启事务
@Transactional(propagation=Propagation.NOT_SUPPORTED)
//不管是否存在事务, 都创建一个新的事务, 原来的挂起, 新的执行完毕, 继续执行老的事务
@Transactional(propagation=Propagation.REQUIRES_NEW)
//必须在一个已有的事务中执行, 否则抛出异常
@Transactional(propagation=Propagation.MANDATORY)
//必须在一个没有的事务中执行, 否则抛出异常(与Propagation.MANDATORY相反)
@Transactional(propagation=Propagation.NEVER)
//如果其他bean调用这个方法, 在其他bean中声明事务, 那就用事务, 如果其他bean没有声明事务, 那就不用事务
@Transactional(propagation=Propagation.SUPPORTS)
5.2 Spring事务失效的场景
- 事务方法未被Spring管理
- 方法使用final类型修饰
- 非public修饰的方法
- 同一个类中的方法相互调用
- 异常被内部catch,程序生吞异常
- 数据库不支持事务,比如mysql,mysql老的存储引擎MyIsam不支持,新的InnoDB支持
- 多线程相互调用,两个方法不在同一个线程中,从而是两个不同的事务。
6.AOP,AOP你怎么使用的?
答:利用AOP+Swagger注解实现日志记录功能。 打印调用接口的入参出参,创建一个 AOP 切面类,只要在类上加个 @Aspect 注解即可。@Aspect 注解用来描述一个切面类,定义切面类的时候需要打上这个注解。@Component 注解将该类交给 Spring 来管理。在这个类里实现 advice:写好服务(@Before—方法开始前,@AfterRunning—方法结束后),然后用@pointCut自定义一个切点,我指定的是加了@ApiOpreration注解的(用法:@Pointcut("@annotation(ApiOpreration)"),@annotation表示用在后面这个注解上),都织入我这个切面,然后在方法调用上,需要的地方加入@ApiOpreration这个注解,即可把这个切面用上。
如果是自定义注解 :则自己定义一个接口加上这个下面注解@Target({ElementType.METHOD,ElementType.TYPE}) 表示是一个自定义注解接口,可以用在方法上,其他都和上面一样
7.微服务里的分布式事务?
答:cap理论(c –一致性 ,a-可用性 ,p-分区容忍性)
分布式解决方案 : 二阶段提交,三阶段提交
在计算机中部分关系数据库如 Oracle、MySQL 支持两阶段提交协议,
- 准备阶段(Prepare phase):事务管理器给每个参与者发送 Prepare 消息,每个数据库参与者在本地执行事务,并写本地的 Undo/Redo 日志,此时事务没有提交。(Undo 日志是记录修改前的数据,用于数据库回滚,Redo 日志是记录修改后的数据,用于提交事务后写入数据文件)
- 提交阶段(commit phase):如果事务管理器收到了参与者的执行失败或者超时消息时,直接给每个参与者发送回滚(Rollback)消息;否则,发送提交(Commit)消息;参与者根据事务管理器的指令执行提交或者回滚操作,并释放事务处理过程中使用的锁资源。注意:必须在最后阶段释放锁资源。
8.redis是单线程还是多线程?
答:分版本,以前老版本的redis是单线程的,但现在新版本的redis,命令工作线程是单线程的,其他功能,比如持久化RBD、AOF、异步删除、集群数据同步等,其实是由额外的线程执行的。
Redis在3.x版本时,单线程性能依旧很快的主要原因:
1.基于内存操作: Redis的所有数据都存在内存中,因此所有的运算都是内存级别的
2.数据结构简单: Redis的数据结构是专门设计的,而这些简单的数据结构的查找和操作时间复杂度都是O(1)
3.多路复用和非阻塞IO: Redis使用IO多路复用功能来监听多个socket连接客户端,这样就可以使用一个线程连接来处理多个请求,减少线程切换带来的开销,同时也避免了IO阻塞操作
4.避免上下文切换: 因为是单线程模型,因此就避免了不必要的线程上下文切换和多线程竞争,省去了多线程切换带来的时间和性能上的消耗
9多级缓存?
答:二级缓存,以本地缓存作为一级缓存,redis作为二级缓存,
1、本地缓存----Caffeine等封装好的工具
本地缓存的概念:
本地缓存是指和应用程序在同一个进程内的内存空间去存储数据,数据的读写都是在同一个进程内完成的。
本地缓存优点:
读取速度快,但是不能进行大数据量存储。
本地缓存不需要远程网络请求去操作内存空间,没有额外的性能消耗,所以读取速度快。
本地缓存缺点:
应用程序集群部署时,会存在数据更新问题(数据更新不一致)所以基于redis的发布/订阅机制来实现各个部署节点的数据同步更新。
2、分布式缓存
Redis作为二级缓存。
在应用程序集群部署时,如果数据库的数据有更新的情况,一级缓存的数据更新容易出现数据不一致的情况。因为是集群部署,多个部署节点实现一级缓存数据更新难度比较大,不过我们可以通过Redis的消息发布/订阅机制来实现多个节点缓存数据一致性问题。Redis中发布与订阅通过PUBLISH和SUBSCRIBE命令实现
补充问题:怎么使用本地缓存的开启与否
定义一个总的缓存配置类和另外两个配置类-----本地缓存配置类和redis配置类,然后在总缓存配置类中使用@ConditionalOnProperty注解,通过其两个属性name以及havingValue来实现的,其中name用指定为本地缓存配置类中的配置路径,在本地缓存配置类中的指定配置中配置在配置中心开启本地缓存的配置的路径,这个时候总缓存配置类中ConditionalOnProperty注解就会去读取本地缓存配置类中的路径的结果,判断
- 如果该值为空,则返回false;
- 如果值不为空,则将该值与havingValue指定的值进行比较,如果一样则返回true;否则返回false。
- 如果返回值为false,则该configuration不生效,则本地缓存配置部分不会给实例化到总配置类中,( 总配置类里面写了两个注入,一个单独的redis注入,和一个本地缓存咖啡因的注入)redis的配置类会给实例化,则后续查询只会去查询redis;
- 为true则这个配置类生效,则本地缓存配置类优先加载,在里面redis配置类作为构造函数传入了本地缓存配置类,如果本地缓存查询结果为空,就去用redis配置类去查询数据并写回本地缓存。
10. beanFactory和applicationContext区别
11.springboot 和springMvc有什么区别
12:使用mq遇到什么问题?
答:先介绍各种mq的差别,然后再单独说消息丢失处理方案,如果是大批量消息导致消息丢失,首先考虑选型改变,卡夫卡更适合大批量消息。
13:为什么不建议使用Executors类创建线程池?
答:1. 隐藏关键配置参数:Executors提供的便捷方法通常会隐藏线程池的重要配置参数,比如线程池的大小、工作队列类型及容量、拒绝策略等。这限制了开发者对线程池行为的精确控制和优化,可能导致资源使用不当或性能问题。
2. 潜在的资源耗尽风险:
Executors类里的 `newFixedThreadPool`和`newSingleThreadExecutor`使用的是无界队列,这意味着如果生产任务的速度超过消费速度,队列会无限增长,最终可能导致内存耗尽(Out Of Memory Error)。
3. 推荐直接通过new ThreadPoolExecutor来显式地指定线程池参数,以提高代码的健壮性和可维护性。
14: 线程池有哪些状态?
答:线程池的状态有以下 5 种:
- RUNNING:运行状态,线程池创建好之后就会进入此状态,如果不手动调用关闭方法,那么线程池在整个程序运行期间都是此状态。
- SHUTDOWN:关闭状态,不再接受新任务提交,但是会将已保存在任务队列中的任务处理完。
- STOP:停止状态,不再接受新任务提交,并且会中断当前正在执行的任务、放弃任务队列中已有的任务。
- TIDYING:整理状态,所有的任务都执行完毕后(也包括任务队列中的任务执行完),当前线程池中的活动线程数降为 0 时的状态。到此状态之后,会调用线程池的 terminated() 方法。
- TERMINATED:销毁状态,当执行完线程池的 terminated() 方法之后就会变为此状态。
15:什么是分布式,和微服务有什么区别?
答:分布式:不同系统部署在不同的服务器,通过网络方式来通信,或者一个服务在集群部署,微服务主要是针对系统的,是系统的架构方式,微服务可以是分布式也可以不是,多个系统也可以部署在一个服务器上,分布式是不同系统之间的部署
16:对象的创建过程?
17:jvm内存泄漏的几种可能的情况?
答:1、循环引用:在使用面向对象的编程语言时,经常会出现两个或多个对象彼此引用,导致它们之间形成了循环引用,使得这些对象无法被垃圾回收器及时释放。
2、threadLocal的错误使用,values是强引用,不被回收
3、静态集合的生命周期和jvm一样,不会给垃圾回收器回猴,
4.对象的哈希值产生变化,无法找到并删除
18. 通信协议有哪些?
19. hashMap的扩容
答:是有个扩容因子决定的,默认是0.75,可以改变,链表化树的阈值是8
20. spring的核心模块有哪些
21. 引用计数法的缺点
答:对于循环调用,计数器永远不为0,没法回收,计数过程是浪费资源的,计数器额外占用内存
22. mabatis执行流程
答:
在创建sqlSeeion对象后,会去调一个getMapper方法,下面是获取mapper的过程
MapperProxyFactory里面就是进行一个动态代理的