只需要在我们的查询语句前加 explain/desc即可
例如,查询执行计划
EXPLAIN SELECt * FROM SYS_USER WHERe USER_ID = 1
结果如下:
其中比较重要需要关注的几个点是:
1)id
查询执行顺序:
id 值相同时表示从上向下执行
id 值相同被视为一组
如果是子查询,id 值会递增,id 值越高,优先级越高
id为NULL最后执行。
2)type
显示连接使用了何种类型。从最好到最差的连接类型为 system > const > eq_reg > ref > range > index > ALL。
一般来说,得保证查询达到range级别,最好达到ref。
3)key
实际使用的索引。如果为 NULL,则没有使用索引。
4)ref
显示索引的哪一列被使用了,如果可能的话,是一个常量 const。
5)Extra
MYSQL 如何解析查询的额外信息。
2 Springboot自动装配原理是什么?自动装配大致流程是通过@SpringBootApplication进行实现,这个注解声明在SpringBoot的启动类上。
1.SpringBoot启动类
2、@SpringBootApplication注解
SpringBoot启动类=>@SpringBootApplication
3、@SpringBootConfiguration注解
SpringBoot启动类=>@SpringBootApplication=>@SpringBootConfiguration
通过@SpringBootConfiguration注解标识SpringBootApplication是一个SpringBoot配置类
@AliasFor注解用于为注解属性声明别名(@SpringBootApplication注解也有@AliasFor注解)
4、@EnableAutoConfiguration注解
SpringBoot启动类=>@SpringBootApplication=>@EnableAutoConfiguration
通过@EnableAutoConfiguration注解实现自动装配
5、@AutoConfigurationPackage注解SpringBoot启动类=>@SpringBootApplication=>@EnableAutoConfiguration=>@AutoConfigurationPackage
通过@AutoConfigurationPackage注解将添加该注解的类所在的package作为自动配置package进行管理
通过AutoConfigurationPackages工具类获取自动配置package列表,也就是说当SpringBoot应用启动时默认会将启动类所在的package作为自动配置的package
6、@EnableAutoConfiguration注解最重要的是AutoConfigurationImportSelector.class,将需要装配的类装配到IoC容器中,下面重点分析一下这个类的实现
1)selectImport()
AutoConfigurationImportSelector中的selectImport方法是自动装配的核心实现,它主要是读取META-INF/spring.factories文件,经过去重、过滤,返回需要装配的配置类集合。
2)selectImport()=>AutoConfigurationMetadataLoader.loadMetadata()
在META-INF/spring-autoconfigure-metadata.properties文件内容属性中看可以看到配置了很多组件的键值对属性。
3)selectImport() => AutoConfigurationMetadataLoader.loadMetadata() => PropertiesLoaderUtils.loadProperties()
最后创建并返回的AutoConfigurationMetadata对象
4)selectImport() => getAutoConfigurationEntry()
protected AutoConfigurationEntry getAutoConfigurationEntry(AutoConfigurationMetadata autoConfigurationMetadata, AnnotationMetadata annotationMetadata) {
// 再次判断自动装配开关是否打开
if (!isEnabled(annotationMetadata)) {
return EMPTY_ENTRY;
}
// 获取 @EnableAutoConfiguration注解的 exclude 和 excludeName 属性
AnnotationAttributes attributes = getAttributes(annotationMetadata);
// 获取该依赖下的 spring.factories配置文件的内容
List configurations = getCandidateConfigurations(annotationMetadata, attributes);
// 移除重复的数据
configurations = removeDuplicates(configurations);
//获取spring.autoconfigure.exclude 配置文件的内容并与exclude 和 excludeName 属性合并到一个集合中
Set exclusions = getExclusions(annotationMetadata, attributes);
//检验configurations中需要排除的内容
checkExcludedClasses(configurations, exclusions);
//检验configurations中需要排除的内容
configurations.removeAll(exclusions);
// 再次对configurations中的内容进行过滤
configurations = filter(configurations, autoConfigurationMetadata);
// 关闭spring监听器中的自动装配事件
fireAutoConfigurationImportEvents(configurations, exclusions);
return new AutoConfigurationEntry(configurations, exclusions);
}
getAttributes方法就是获取 @EnableAutoConfiguration注解的 exclude 和 excludeName 属性
5)selectImport() => getAutoConfigurationEntry() => getCandidateConfigurations() =>SpringFactoriesLoader.loadFactoryNames()
总结:
1)通过注解@SpringBootApplication=>@EnableAutoConfiguration=>@Import({AutoConfigurationImportSelector.class})实现自动装配
2)AutoConfigurationImportSelector类中重写了ImportSelector中selectImports方法,批量返回需要装配的配置类
3)通过Spring提供的SpringFactoriesLoader机制,扫描classpath下的META-INF/spring.factories文件,读取需要自动装配的配置类
4)依据条件筛选的方式,把不符合的配置类移除掉,最终完成自动装配
3 SpringMVC执行流程是什么?1、 用户向服务端发送一次请求,这个请求会先到前端控制器DispatcherServlet(也叫中央控制器)。
2、DispatcherServlet接收到请求后会调用HandlerMapping处理器映射器。由此得知,该请求该由哪个Controller来处理(并未调用Controller,只是得知)
3、DispatcherServlet调用HandlerAdapter处理器适配器,告诉处理器适配器应该要去执行哪个Controller
4、HandlerAdapter处理器适配器去执行Controller并得到ModelAndView(数据和视图),并层层返回给DispatcherServlet
5、DispatcherServlet将ModelAndView交给ViewReslover视图解析器解析,然后返回真正的视图。
6、DispatcherServlet将模型数据填充到视图中
7、DispatcherServlet将结果响应给用户
第一类是支持当前事务,有3种
1)REQUIRED (必须有)
如果当前方法没有事务,新建一个事务,如果已经存在一个事务中,则加入到这个事务中。
2)SUPPORTS (可有可无)
支持当前事务,如果当前没有事务,就以非事务方式执行
3)MANDATORY (强制)
使用当前的事务,如果当前没有事务,就抛出异常。
第二类是不支持当前事务,有3种
4)REQUIRES_NEW
新建事务,如果当前存在事务,把当前事务挂起。
5)NOT_SUPPORTED
以非事务方式执行操作,如果当前存在事务,就把当前事务挂起。
6)NEVER
以非事务方式执行,如果当前存在事务,则抛出异常。
第三类:
7)NESTED
5 Spring 框架中单例Bean是否线程安全?如果当前存在事务,则在嵌套事务内执行。如果当前没有事务,则执行与PROPAGATION_REQUIRED类似的操作。
Spring框架中的单例Bean默认是单例模式,不是线程安全的。Spring框架并没有对单例Bean进行多线程的封装处理。
关于线程是否安全,可以从Bean的状态来考虑是否要进行处理。
有状态的Bean就是有数据存储功能,例如VO视图对象,无状态的Bean是不会保存数据的,例如DAO类。
实际上大部分时候Spring Bean都是无状态的,因此某种程度上来说,Bean也是安全的,但如果Bean有状态的话,那就要开发者自己去保证线程安全了,可以通过把Bean的作用域改为“prototype”,这样可以保证线程安全。
不要在bean中声明任何有状态的实例变量或类变量,如果必须如此,那么就使用ThreadLocal把变量变为线程私有的,如果bean的实例变量或类变量需要在多个线程之间共享,那么就只能使用synchronized、lock、CAS等这些实现线程同步的方法了。
6 Spring中使用了哪些设计模式及应用场景1.工厂模式:Spring使用工厂模式通过BeanFactory和ApplicationContext创建bean对象。
2.代理模式:Spring AOP功能的实现。
3.单例模式:Spring中的bean默认都是单例的。
4.模板模式:Spring中的jdbcTemplate、hibernateTemplate等以Template结尾的对数据库操作的类,它们就使用到了模板模式。
5.包装器模式:我们的项目需要连接多个数据库,而且不同的客户在每次访问中根据需要会去访问不同的数据库。这种模式让我们可以根据客户的需求能够动态切换不同的数据源。
6.观察者模式:Spring事件驱动模型就是观察者模式很经典的一个应用。
7.适配器模式:Spring AOP的增强或通知(Advice)使用到了适配器模式、Spring MVC中也是用到了适配器模式适配Controller。
8.策略模式:Spring框架的资源访问Resource接口,该接口提供了更强的资源访问能力,Spring框架本身大量使用了Resource接口来访问底层资源。
7 Spring事务的隔离级别有哪些?1.DEFAULT:采用 DB 默认的事务隔离级别
2.READ_UNCOMMITTED:读未提交
3.READ_COMMITTED:读已提交
4.REPEATABLE_READ:可重复读
5.SERIALIZABLE:串行化
8 Spring事务的实现方式原理是什么?在使用Spring框架时,有两种使用事务的方式。一种是编程式的,一种是声明式(@Transactional注解)。
首先,事务这个概念是数据库层面的,Spring只是基于数据库中的事务进行了扩展,以及提供了一些能让程序员更加方便操作事务的方式。
比如我们可以通过在某个方法上面增加@Transactional注解,就可以开启事务,这个方法中所有的sql都会在一个事务中执行,统一成功或失败。
在一个方法上加了@Transactional注解后,Spring会基于这个类生成一个代理对象,会将这个代理对象作为bean。
当在使用这个代理对象的方法时,如果这个方法上存在@Transactional注解,那么代理逻辑会先把事务的自动提交设置为false,然后再去执行原本的业务逻辑方法,如果执行中没有出现异常,那么代理逻辑就会将事务提交,如果出现了异常,那么就会将事务进行回滚。
当然,针对哪些异常回滚事务是可以配置的,可以利用@Transactional注解中的rollbackFor属性进行配置,默认情况会对RuntimeException和Error进行回滚。
9 Spring事务什么时候会失效?1)访问权限问题
Java的访问权限主要有三种:private、protected、public,它们的权限从左到右,依次变大,spring要求被代理方法必须是public的。如果我们在开发过程中,把有某些事务方法,定义了错误的访问权限,就会导致事务功能出问题
2)方法是final修饰的
当某个方法被final修饰时,子类是无法继承和重载的,事务是基于动态代理去实现的,如果某个方法用final修饰了,那么在它的代理类中,就无法重写该方法,而添加事务功能。
3)未被Spring管理
使用spring事务的前提是:对象要被spring管理,需要创建bean实例。比如,你开发了一个Service类但忘了加@Service注解又或者XML里面配置纳入Spring管理的包文件路径配置错误等。
4)错误的传播特性
我们在使用@Transactional注解时,是可以指定propagation参数的。该参数的作用是指定事务的传播特性
5)自己吞了异常
事务不会回滚,最常见的问题是:开发者在代码中手动try…catch了异常。
这种情况下spring事务当然不会回滚,因为开发者自己捕获了异常,又没有手动抛出,换句话说就是把异常吞掉了。
如果想要spring事务能够正常回滚,必须抛出它能够处理的异常。如果没有抛异常,则spring认为程序是正常的。
6)手动抛了别的异常
即使开发者没有手动捕获异常,但如果抛的异常不正确,spring事务也不会回滚。
因为spring事务,默认情况下只会回滚RuntimeException(运行时异常)和Error(错误),对于普通的Exception(非运行时异常),它不会回滚。
7)自定义了回滚异常
@Transactional注解声明事务时,有时我们想自定义回滚的异常,spring也是支持的。可以通过设置rollbackFor参数,来完成这个功能。
@Service
public class OrderService {
@Transactional(rollbackFor = BusinessException.class)
public void add(OrderVO orderVO) {
saveData(orderVO);
}
}
如上如果程序报错了,抛了SqlException、NullPointerException等异常。而BusinessException是我们自定义的异常,报错的异常不属于BusinessException,所以事务也不会回滚。
8)方法内部调用
有时候我们需要在某个Service类的某个方法中,调用另外一个事务方法。
@Service
public class OrderService {
@Transactional
public void add(OrderVO orderVO) {
saveData(orderVO);
}
@Transactional
public void saveData(OrderVO orderVO) {
doSameThing();
}
}
我们看到在事务方法add中,直接调用事务方法saveData。saveData方法拥有事务的能力是因为Spring Aop生成代理了对象,但是这种方法直接调用了this对象的方法,所以saveData方法不会生成事务。
由此可见,在同一个类中的方法直接内部调用,会导致事务失效。
10 Spring支持的bean作用域有哪些?Spring容器中bean的作用域可以分为5个范围:
1)singleton
默认,每个容器中只有一个bean的实例,单例的模式由BeanFactory自身来维护。
2)prototype
为每一个bean请求提供一个实例。
3)request
为每一个网络请求创建一个实例,在请求完成以后,bean会失效并被垃圾回收器回收。
4)session
与request范围类似,确保每个session中有一个bean的实例,在session过期后,bean会随之失效。
5)global-session
全局作用域,global-session和Portlet应用相关。当你的应用部署在Portlet容器中工作时,它包含很多portlet。如果你想要声明让所有的portlet共用全局的存储变量的话,那么这全局变量需要存储在global-session中。全局作用域与Servlet中的session作用域效果相同。



