MyBatis Plus插件
MyBatis Plus提供了分页插件PaginationInterceptor、执行分析插件SqlExplainInterceptor、性能分析插件PerformanceInterceptor以及乐观锁插件OptimisticLockerInterceptor。
Mybatis 通过插件 (Interceptor) 可以做到拦截四大对象相关方法的执行 ,根据需求完成相关数据的动态改变。
四大对象是:
Executor
StatementHandler
ParameterHandler
ResultSetHandler
四大对象的每个对象在创建时,都会执行interceptorChain.pluginAll(),会经过每个插件对象的 plugin()方法,目的是为当前的四大对象创建代理。代理对象就可以拦截到四大对象相关方法的执行,因为要执行四大对象的方法需要经过代理 。
① xml下插件的配置
如下所示:
② springboot下注册插件
这里以分页插件为例:
@Bean public PaginationInterceptor paginationInterceptor()
{
PaginationInterceptor paginationInterceptor = new PaginationInterceptor();
// 设置请求的页面大于最大页后操作, true调回到首页,false 继续请求 默认false
// paginationInterceptor.setOverflow(false);
// 设置最大单页限制数量,默认 500 条,-1 不受限制
// paginationInterceptor.setLimit(500);
// 开启 count 的 join 优化,只针对部分 left join
paginationInterceptor.setCountSqlParser(new JsqlParserCountOptimize(true));
return paginationInterceptor;
}
③ SqlExplainInterceptor
SQL执行分析拦截器,全类名是com.baomidou.mybatisplus.plugins.SqlExplainInterceptor,只支持 MySQL5.6.3以上版本。
该插件的作用是分析 DELETE UPDATE语句 ,防止小白或者恶意进行DELETE UPDATE全表操作,不建议在生产环境中使用会造成性能下降,
在插件的底层通过SQL语句分析命令 Explain 分析当前的 SQL语句,根据结果集中的 Extra列来断定当前是否全表操作。
④ 性能分析插件
性能分析拦截器,全类名是com.baomidou.mybatisplus.plugins.PerformanceInterceptor,用于输出每条 SQL 语句及其执行时间。SQL性能执行分析 ,开发环境使用 超过指定时间,停止运行。
⑤ 乐观锁插件
全类名是com.baomidou.mybatisplus.plugins.OptimisticLockerInterceptor。如果想实现如下需求 : 当要更新一条记录的时候,希望这条记录没有被别人更新,就可以使用该插件进行判断。
乐观锁的实现原理(@Version 用于注解实体字段,必须要有) :
取出记录时,获取当前 version
更新时,带上这个version
执行更新时,set version = yourVersion+1 where version = yourVersion
如果 version不对,就更新失败
【2】获取sqlSessionFactoryBean
如下图所示,在系统启动时会初始化定义的bean。DefaultListableBeanFactory.preInstantiateSingletons方法中会从beanDefinitionNames中获取bean name然后依次创建。
这里可以看到RootBeanDefinition是com.baomidou.mybatisplus.spring.MybatisSqlSessionFactoryBean。
① 获取bean的过程中bean属性
如下所示,在getBean过程中可以看到bean的属性:
② createBean
第一次获取bean的时候会走到AbstractAutowireCapableBeanFactory.createBean进行bean的创建。
/** 创建一个bean实例,为bean实例设置属性值,调用post-processors-bean后置处理器 */@Overrideprotected Object createBean(String beanName, RootBeanDefinition mbd, Object[] args)
throws BeanCreationException
{//...暂时忽略其他代码
try {// 这里会首先触发BeanPostProcessors ,如果这里能获取到bean则直接返回,不再走doCreateBean
Object bean = resolveBeforeInstantiation(beanName, mbdToUse);
if (bean != null)
{
return bean;
} }//...暂时忽略其他代码
在AbstractAutowireCapableBeanFactory.resolveBeforeInstantiation中就会分别执行bean后置处理器的前置和后置方法。
protected Object resolveBeforeInstantiation(String beanName, RootBeanDefinition mbd)
{ Object bean = null;
if (!Boolean.FALSE.equals(mbd.beforeInstantiationResolved))
{
// Make sure bean class is actually resolved at this point.
if (!mbd.isSynthetic() && hasInstantiationAwareBeanPostProcessors())
{
Class> targetType = determineTargetType(beanName, mbd);
if (targetType != null) {
bean = applyBeanPostProcessorsBeforeInstantiation(targetType, beanName);
if (bean != null)
{
bean = applyBeanPostProcessorsAfterInitialization(bean, beanName);
}
}
}
mbd.beforeInstantiationResolved = (bean != null);
}
return bean;
}
执行后置处理器的前置方法如下所示:
③ doCreateBean
AbstractAutowireCapableBeanFactory.doCreateBean是创建bean的核心方法,这会为bean属性赋值并会触发bean后置处理器、InitializingBean以及自定init方法等。
protected Object doCreateBean(final String beanName, final RootBeanDefinition mbd, final Object[] args) throws BeanCreationException
{
// Instantiate the bean.--实例化beanBeanWrapper instanceWrapper = null;if (mbd.isSingleton()) { instanceWrapper = this.factoryBeanInstanceCache.remove(beanName);}if (instanceWrapper == nu