通用Mapper是一款針對mybatis進行擴展的輕量級組件,使用起來非常方便。當調用其針對mysql進行批量添加數據的方法時,發現報錯,仔細研究了一番,發現是在使用通用Mapper上出現了問題。下面貼出本文使用的通用的Mapper github 地址及其版本。
通用Mapper github主頁:https://github.com/abel533/Mapper/ 本文示例使用的版本是3.5.4-SNAPSHOT 該分支的鏈接: https://github.com/abel533/Mapper/tree/3.5.x
繼承通用Mapper的DAO層示例代碼:
package com.github.torlight.sbex; import tk.mybatis.mapper.common.Mapper; import tk.mybatis.mapper.common.MySqlMapper; public interface TEntityDAO extends Mapper<TEntityDO>,MySqlMapper<TEntityDO>{ }
批量添加數據的示例代碼:
package com.github.torlight.sbex; import java.util.ArrayList; import java.util.List; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.context.ApplicationContext; @SpringBootApplication public class Example3Main { public static void main(String[] args) { ApplicationContext ctx=SpringApplication.run(Example3Main.class, args); System.out.println("Example3Main running..."); List<TEntityDO> tEntityDOList=new ArrayList<TEntityDO>(10); tEntityDOList.add(new TEntityDO("1")); tEntityDOList.add(new TEntityDO("2")); tEntityDOList.add(new TEntityDO("3")); tEntityDOList.add(new TEntityDO("4")); tEntityDOList.add(new TEntityDO("5")); tEntityDOList.add(new TEntityDO("6")); tEntityDOList.add(new TEntityDO("7")); tEntityDOList.add(new TEntityDO("8")); tEntityDOList.add(new TEntityDO("9")); tEntityDOList.add(new TEntityDO("10")); TEntityDAO tEntityDAO=ctx.getBean(TEntityDAO.class); tEntityDAO.insertList(tEntityDOList); } }
運行程序后,出現如下錯誤:
Exception in thread "main" org.mybatis.spring.MyBatisSystemException: nested exception is org.apache.ibatis.builder.BuilderException: Error invoking SqlProvider method (tk.mybatis.mapper.provider.SpecialProvider.dynamicSQL). Cause: java.lang.InstantiationException: tk.mybatis.mapper.provider.SpecialProvider at org.mybatis.spring.MyBatisExceptionTranslator.translateExceptionIfPossible(MyBatisExceptionTranslator.java:77) at org.mybatis.spring.SqlSessionTemplate$SqlSessionInterceptor.invoke(SqlSessionTemplate.java:446) at com.sun.proxy.$Proxy62.insert(Unknown Source) at org.mybatis.spring.SqlSessionTemplate.insert(SqlSessionTemplate.java:278) at org.apache.ibatis.binding.MapperMethod.execute(MapperMethod.java:57) at org.apache.ibatis.binding.MapperProxy.invoke(MapperProxy.java:59) at com.sun.proxy.$Proxy63.insertList(Unknown Source) at com.github.torlight.sbex.Example3Main.main(Example3Main.java:33) Caused by: org.apache.ibatis.builder.BuilderException: Error invoking SqlProvider method (tk.mybatis.mapper.provider.SpecialProvider.dynamicSQL). Cause: java.lang.InstantiationException: tk.mybatis.mapper.provider.SpecialProvider at org.apache.ibatis.builder.annotation.ProviderSqlSource.createSqlSource(ProviderSqlSource.java:103) at org.apache.ibatis.builder.annotation.ProviderSqlSource.getBoundSql(ProviderSqlSource.java:73) at org.apache.ibatis.mapping.MappedStatement.getBoundSql(MappedStatement.java:292) at org.apache.ibatis.executor.statement.BaseStatementHandler.<init>(BaseStatementHandler.java:64) at org.apache.ibatis.executor.statement.PreparedStatementHandler.<init>(PreparedStatementHandler.java:40) at org.apache.ibatis.executor.statement.RoutingStatementHandler.<init>(RoutingStatementHandler.java:46) at org.apache.ibatis.session.Configuration.newStatementHandler(Configuration.java:545) at org.apache.ibatis.executor.SimpleExecutor.doUpdate(SimpleExecutor.java:48) at org.apache.ibatis.executor.BaseExecutor.update(BaseExecutor.java:117) at org.apache.ibatis.executor.CachingExecutor.update(CachingExecutor.java:76) at org.apache.ibatis.session.defaults.DefaultSqlSession.update(DefaultSqlSession.java:198) at org.apache.ibatis.session.defaults.DefaultSqlSession.insert(DefaultSqlSession.java:185) at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57) at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) at java.lang.reflect.Method.invoke(Method.java:606) at org.mybatis.spring.SqlSessionTemplate$SqlSessionInterceptor.invoke(SqlSessionTemplate.java:433) ... 6 more Caused by: java.lang.InstantiationException: tk.mybatis.mapper.provider.SpecialProvider at java.lang.Class.newInstance(Class.java:364) at org.apache.ibatis.builder.annotation.ProviderSqlSource.createSqlSource(ProviderSqlSource.java:85) ... 22 more
當出現該錯誤之后,隨手在網上搜索了一把,看看別人是怎么解決的。找到如下一篇文章(文章的鏈接如下文),非常遺憾該文章也沒有給出更加實際的解決辦法。
tk.mybatis.mapper.provider.SpecialProvider.<init>() 原文鏈接地址:https://www.cnblogs.com/softidea/p/6624766.html
我把目光停留在了用於訪問數據庫的DAO層 TEntityDAO 類上面,該接口繼承了Mapper和MySqlMapper 兩個接口,這兩個接口有啥區別呢? 帶着這個疑問,我進入到這兩個接口。細看了兩個接口之后,發現Mapper只是提供普通的CRUD,而批量添加數據接口在后者。兩者區別在這兒。下面貼出這兩個接口的截圖。

通用Mapper接口

批量添加接口
看到這兩個接口的區別,回想到通用Mpper配置,配置掃描時時只添加了通用Mapper接口,tk.mybatis.mapper.common.Mapper ,是不是也要把批量添加的接口也要添加到接口掃描配置里面。
通用接口掃描代碼:
@Bean public MapperScannerConfigurer mapperScannerConfigurer(){ Properties properties=new Properties(); properties.put("mappers","tk.mybatis.mapper.common.Mapper"); MapperScannerConfigurer msc=new MapperScannerConfigurer(); msc.getMapperHelper().setProperties(properties); msc.setBasePackage(DataSourceConfig.PACKAGE); msc.setSqlSessionFactoryBeanName(DataSourceConfig.SESSION_FACTORY_BEAN_NAME); return msc; }
修改后的通用接口掃描代碼:
@Bean public MapperScannerConfigurer mapperScannerConfigurer(){ Properties properties=new Properties(); properties.put("mappers","tk.mybatis.mapper.common.Mapper,tk.mybatis.mapper.common.MySqlMapper"); MapperScannerConfigurer msc=new MapperScannerConfigurer(); msc.getMapperHelper().setProperties(properties); msc.setBasePackage(DataSourceConfig.PACKAGE); msc.setSqlSessionFactoryBeanName(DataSourceConfig.SESSION_FACTORY_BEAN_NAME); return msc; }
重新運行程序后,還真是這兒的原因。
總結:通用Mapper基本的CRUD方法和批量操作數據庫的方法不是放在一起,需要由程序按需加載。
示例代碼已經上傳到github,代碼中沒有數據庫相關的配置,運行代碼之前,需要把數據庫相關的配置補上。
完整的代碼見:https://github.com/gittorlight/springboot-example/tree/master/example3
