SpringBoot整合Mybatis自定义 * 不起作用的处理方案

作者:小胖学编程 时间:2023-03-19 04:35:14 

SpringBoot整合Mybatis自定义 * 不起作用

Mybatis插件生效的方式:

1. 原始的读取mybatis-config.xml文件

该方式和Spring无关,是通过反射的形式创建插件对象,此时会执行org.apache.ibatis.plugin.Interceptor#setProperties方法,以读取配置参数。


mybatis:
 mapper-locations: classpath*:/mapping/*.xml
 type-aliases-package: com.tellme.pojo
 #读取全局配置的地址
 config-location: classpath:mybatis-config.xml

在resource目录下配置mybatis的全局配置:


<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE configuration PUBLIC "-//mybatis.org//DTD Config 3.0//EN" "http://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration>
   <settings>
       <setting name="cacheEnabled" value="true"/>
       <setting name="lazyLoadingEnabled" value="true"/>
       <setting name="multipleResultSetsEnabled" value="true"/>
       <setting name="useColumnLabel" value="true"/>
       <setting name="mapUnderscoreToCamelCase" value="true"/>
       <setting name="useGeneratedKeys" value="true"/>
       <setting name="defaultExecutorType" value="SIMPLE"/>
       <setting name="defaultStatementTimeout" value="25000"/>
   </settings>
   <typeAliases>
       <typeAlias alias="Integer" type="java.lang.Integer"/>
       <typeAlias alias="Long" type="java.lang.Long"/>
       <typeAlias alias="HashMap" type="java.util.HashMap"/>
       <typeAlias alias="LinkedHashMap" type="java.util.LinkedHashMap"/>
       <typeAlias alias="ArrayList" type="java.util.ArrayList"/>
       <typeAlias alias="LinkedList" type="java.util.LinkedList"/>
   </typeAliases>
   <!--配置的插件名-->
   <plugins>
       <plugin interceptor="com.xxx.yyy.plugins.PrintSqlInfoInterceptor"/>
   </plugins>
</configuration>

2. 与SpringBoot容器整合

网上很多方案说:mybatis自定义 * 上加上@Component注解便可以生效。但是我将自定义 * 放入到Spring容器中,自定义 * 却失效了。

然后找到了springboot配置多数据源后mybatis * 失效文章,说是自定义配置了数据源导致了 * 失效。

2.1 mybatis的自动装载

源码位置:org.mybatis.spring.boot.autoconfigure.MybatisAutoConfiguration


@Configuration
@ConditionalOnClass({ SqlSessionFactory.class, SqlSessionFactoryBean.class })
@ConditionalOnBean(DataSource.class)
@EnableConfigurationProperties(MybatisProperties.class)
@AutoConfigureAfter(DataSourceAutoConfiguration.class)
public class MybatisAutoConfiguration {
 private static Log log = LogFactory.getLog(MybatisAutoConfiguration.class);
 @Autowired
 private MybatisProperties properties;
  //会依赖注入Spring容器中所有的mybatis的Interceptor *
 @Autowired(required = false)
 private Interceptor[] interceptors;
  ...
 @Bean
 @ConditionalOnMissingBean
 public SqlSessionFactory sqlSessionFactory(DataSource dataSource) throws Exception {
   SqlSessionFactoryBean factory = new SqlSessionFactoryBean();
   factory.setDataSource(dataSource);
   factory.setVfs(SpringBootVFS.class);
   if (StringUtils.hasText(this.properties.getConfigLocation())) {
     factory.setConfigLocation(this.resourceLoader.getResource(this.properties.getConfigLocation()));
   }
   factory.setConfiguration(properties.getConfiguration());
   //手动放入到了setPlugins方法中。
   if (!ObjectUtils.isEmpty(this.interceptors)) {
     factory.setPlugins(this.interceptors);
   }
   if (this.databaseIdProvider != null) {
     factory.setDatabaseIdProvider(this.databaseIdProvider);
   }
   if (StringUtils.hasLength(this.properties.getTypeAliasesPackage())) {
     factory.setTypeAliasesPackage(this.properties.getTypeAliasesPackage());
   }
   if (StringUtils.hasLength(this.properties.getTypeHandlersPackage())) {
     factory.setTypeHandlersPackage(this.properties.getTypeHandlersPackage());
   }
   if (!ObjectUtils.isEmpty(this.properties.resolveMapperLocations())) {
     factory.setMapperLocations(this.properties.resolveMapperLocations());
   }
   return factory.getObject();
 }
  ...
}

上面源码中:自动注入了Interceptor[]数组(我们只需将mybatis的自定义 * 对象放入到Spring容器中)。后续放入了sqlSessionFactory中。

但是项目中虽然自定义配置了sqlSessionFactory类,但却未设置factory.setPlugins(this.interceptors);。导致即使将自定义 * 放入到Spring容器,但却不生效。

解决方法,需要手动修改自定义的sqlSessionFactory类。

3. 在mybatis-config.xml配置又放入Spring容器

这种情况下,mybatis自定义 * 会被执行两次。即在mybatis-config.xml配置的 * 会通过反射的方式创建 * ,放入Spring容器的 * 也会被初始化。

源码位置:org.mybatis.spring.SqlSessionFactoryBean#buildSqlSessionFactory


protected SqlSessionFactory buildSqlSessionFactory() throws IOException {
   Configuration configuration;
   ...读取属性中的plugins,即org.mybatis.spring.SqlSessionFactoryBean#setPlugins设置的。
   if (!isEmpty(this.plugins)) {
       for (Interceptor plugin: this.plugins) {
           configuration.addInterceptor(plugin);
           if (LOGGER.isDebugEnabled()) {
               LOGGER.debug("Registered plugin: '" + plugin + "'");
           }
       }
   }
   ...解析xml配置(通过反射创建 * 对象)
   if (xmlConfigBuilder != null) {
       try {
           xmlConfigBuilder.parse();
           if (LOGGER.isDebugEnabled()) {
               LOGGER.debug("Parsed configuration file: '" + this.configLocation + "'");
           }
       } catch(Exception ex) {
           throw new NestedIOException("Failed to parse config resource: " + this.configLocation, ex);
       } finally {
           ErrorContext.instance().reset();
       }
   }
   return this.sqlSessionFactoryBuilder.build(configuration);
}

最终会执行到:


private void pluginElement(XNode parent) throws Exception {
   if (parent != null) {
       for (XNode child: parent.getChildren()) {
           String interceptor = child.getStringAttribute("interceptor");
           Properties properties = child.getChildrenAsProperties();
           //反射创建mybatis的插件。
           Interceptor interceptorInstance = (Interceptor) resolveClass(interceptor).newInstance();
           interceptorInstance.setProperties(properties);
           configuration.addInterceptor(interceptorInstance);
       }
   }
}

SpringBoot 自定义Mybatis *

开发过程中经常回需要对要执行的sql加以自定义处理,比如分页,计数等。通过 MyBatis 提供的强大机制,使用插件是非常简单的,只需实现 Interceptor 接口,并指定想要拦截的方法签名即可。


@Intercepts({@Signature(type = Executor.class,method = "query",args = {MappedStatement.class,Object.class, RowBounds.class,ResultHandler.class})})
public class MyPageInterceptor implements Interceptor {
   private static final Logger logger= LoggerFactory.getLogger(MyPageInterceptor.class);
   @Override
   public Object intercept(Invocation invocation) throws Throwable {
       logger.warn(invocation.toString());
       return invocation.proceed();
   }
   @Override
   public Object plugin(Object o) {
       return Plugin.wrap(o,this);
   }
   @Override
   public void setProperties(Properties properties) {
       logger.warn(properties.toString());
   }
}

我的配置


mybatis:
 type-aliases-package: me.zingon.pagehelper.model
 mapper-locations: classpath:mapper/*.xml
 configuration:
   map-underscore-to-camel-case: true
   default-fetch-size: 100
   default-statement-timeout: 30

在springboot中要给mybatis加上这个 * ,有三种方法,前两种方法在启动项目时不会自动调用自定义 * 的setProperties方法。

第一种

直接给自定义 * 添加一个@Component注解,当调用sql时结果如下,可以看到 * 生效了,但是启动时候并没有自动调用setProperties方法。

SpringBoot整合Mybatis自定义 * 不起作用的处理方案

第二种

在配置类里添加 * ,这种方法结果同上,也不会自动调用setProperties方法。


@Configuration
public class MybatisConfig {
   @Bean
   ConfigurationCustomizer mybatisConfigurationCustomizer() {
       return new ConfigurationCustomizer() {
           @Override
           public void customize(org.apache.ibatis.session.Configuration configuration) {
               configuration.addInterceptor(new MyPageInterceptor());
           }
       };
   }
}

第三种

这种方法就是跟以前的配置方法类似,在yml配置文件中指定mybatis的xml配置文件,注意config-location属性和configuration属性不能同时指定


mybatis:
 config-location: classpath:mybatis.xml
 type-aliases-package: me.zingon.pagehelper.model
 mapper-locations: classpath:mapper/*.xml

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE configuration PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
       "http://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration>
   <typeAliases>
       <package name="me.zingon.pacargle.model"/>
   </typeAliases>
   <plugins>
       <plugin interceptor="me.zingon.pagehelper.interceptor.MyPageInterceptor">
           <property name="dialect" value="oracle"/>
       </plugin>
   </plugins>
</configuration>

可以看到,在启动项目的时候setProperties被自动调用了

SpringBoot整合Mybatis自定义 * 不起作用的处理方案

前两种方法可以在初始化自定义 * 的时候通过 @Value 注解直接初始化需要的参数。

来源:https://www.jianshu.com/p/5fddb7f67108

标签:SpringBoot,Mybatis,自定义, ,
0
投稿

猜你喜欢

  • Android自定义view实现圆形与半圆形菜单

    2023-10-18 19:08:53
  • SpringBoot消息国际化配置实现过程解析

    2023-05-16 01:19:22
  • Java基于JavaMail实现向QQ邮箱发送邮件

    2021-12-06 13:25:08
  • Android使用onCreateOptionsMenu()创建菜单Menu的方法详解

    2023-05-13 06:21:01
  • 解析Android截取手机屏幕两种实现方案

    2023-12-16 21:28:06
  • Kotlin空安全空类型浅谈

    2022-06-18 22:48:49
  • 详解SpringBoot 快速整合MyBatis(去XML化)

    2022-08-19 16:42:54
  • Java使用arthas修改日志级别详解

    2023-02-04 23:09:26
  • Android Init进程对信号的处理流程详细介绍

    2022-10-25 18:03:31
  • Android多国语言转换Excel及Excel转换为string详解

    2022-10-30 08:07:02
  • MyBatis字段名和属性名不一致的解决方法

    2022-12-15 18:15:22
  • Android Studio使用USB真机调试详解

    2022-05-23 00:49:40
  • Android利用LitePal操作数据库存取图片

    2021-06-14 14:57:45
  • Android编程开发之Spinner组件用法

    2022-09-02 17:55:26
  • VC对自定义资源加密解密(AES)的详解

    2023-01-10 00:27:15
  • Android Apk反编译及加密教程

    2022-01-13 01:01:25
  • 手动添加jar包进Maven本地库内的方法

    2023-08-03 03:10:09
  • Android使用lottie加载json动画的示例代码

    2021-06-20 00:47:01
  • Android 滑动小圆点ViewPager的两种设置方法详解流程

    2023-08-05 03:18:58
  • Java创建类模式_动力节点Java学院整理

    2023-04-15 23:11:55
  • asp之家 软件编程 m.aspxhome.com