在@Configuration中使用通用Mapper会出现无法初始化的问题

1 篇文章 0 订阅
1 篇文章 0 订阅

通用mapper

通用mapper是mybatis的扩展,它提供了一系列的通用方法,避免了冗余的xml编写和公共增删改查的重复劳动。它极大的简化了单表的增删改查,并可以随意的按照自己的需要选择通用方法,还可以很方便的开发自己的通用方法。


本人曾使用spring整合通用mapper一直未出现问题,后来项目升级为spring boot,在整合通用mapper时出现了一个问题,我也曾在github上询问(issues)作者,但作者也未提供好的解决方案。报错如下(截取了一段):

Caused by: org.mybatis.spring.MyBatisSystemException: nested exception is org.apache.ibatis.builder.BuilderException: Error invoking SqlProvider method (tk.mybatis.mapper.provider.base.BaseSelectProvider.dynamicSQL).  Cause: java.lang.InstantiationException: tk.mybatis.mapper.provider.base.BaseSelectProvider
    at org.mybatis.spring.MyBatisExceptionTranslator.translateExceptionIfPossible(MyBatisExceptionTranslator.java:77) ~[mybatis-spring-1.3.1.jar:1.3.1]
    at org.mybatis.spring.SqlSessionTemplate$SqlSessionInterceptor.invoke(SqlSessionTemplate.java:446) ~[mybatis-spring-1.3.1.jar:1.3.1]
    at com.sun.proxy.$Proxy81.selectList(Unknown Source) ~[?:?]
    at org.mybatis.spring.SqlSessionTemplate.selectList(SqlSessionTemplate.java:230) ~[mybatis-spring-1.3.1.jar:1.3.1]
    at org.apache.ibatis.binding.MapperMethod.executeForMany(MapperMethod.java:137) ~[mybatis-3.4.4.jar:3.4.4]
    at org.apache.ibatis.binding.MapperMethod.execute(MapperMethod.java:75) ~[mybatis-3.4.4.jar:3.4.4]
    at org.apache.ibatis.binding.MapperProxy.invoke(MapperProxy.java:59) ~[mybatis-3.4.4.jar:3.4.4]
    at com.sun.proxy.$Proxy82.selectAll(Unknown Source) ~[?:?]

Caused by: org.apache.ibatis.builder.BuilderException: Error invoking SqlProvider method (tk.mybatis.mapper.provider.base.BaseSelectProvider.dynamicSQL).  Cause: java.lang.InstantiationException: tk.mybatis.mapper.provider.base.BaseSelectProvider
    at org.apache.ibatis.builder.annotation.ProviderSqlSource.createSqlSource(ProviderSqlSource.java:103) ~[mybatis-3.4.4.jar:3.4.4]
    at org.apache.ibatis.builder.annotation.ProviderSqlSource.getBoundSql(ProviderSqlSource.java:73) ~[mybatis-3.4.4.jar:3.4.4]
    at org.apache.ibatis.mapping.MappedStatement.getBoundSql(MappedStatement.java:292) ~[mybatis-3.4.4.jar:3.4.4]
    at org.apache.ibatis.executor.CachingExecutor.query(CachingExecutor.java:81) ~[mybatis-3.4.4.jar:3.4.4]
    at org.apache.ibatis.session.defaults.DefaultSqlSession.selectList(DefaultSqlSession.java:148) ~[mybatis-3.4.4.jar:3.4.4]
    at org.apache.ibatis.session.defaults.DefaultSqlSession.selectList(DefaultSqlSession.java:141) ~[mybatis-3.4.4.jar:3.4.4]
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[?:1.8.0_111]
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) ~[?:1.8.0_111]
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) ~[?:1.8.0_111]
    at java.lang.reflect.Method.invoke(Method.java:498) ~[?:1.8.0_111]

作者说这个问题是由于通用mapper没有初始化引起的,我查阅了关于spring boot中Configuration和AutoConfiguration加载顺序的资料,得出问题原因:spring boot中Configuration的加载在AutoConfiguration之前。
but, 为什么mybatis的starter初始化没有问题?
github上的一篇文章解答了这个问题(但我目前没在spring官网找到该描述的出处,如您找到了,请告知,谢谢。)
Configuration和AutoConfiguration加载顺序
我翻看了作者实现starter的源码,发现作者是使用 @PostConstruct 完成通用mapper的初始化的,所以在 Configuration 之后才会初始化,这就引发了以上的错误。
弄明白了问题所在,那该怎么解决呢?


弄明白原因了,其实问题就解决了,我们只要让通用mapper的AutoConfiguration在Configuration之前加载就可以了,但我们没办法在使用作者提供的starter,需要自己来实现。我将实现后的代码放到了github


后来我有翻看了作者的另一个关于mybatis开源项目PageHelper,发现它的starter也是通过 @PostConstruct 实现,所以它也会有上面描述的问题,我把它的starter也修改了,放到了github

  • 1
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: 在 MyBatis 使用 @Param 注解可以向 SQL 映射文件传递参数。 如果在 mapper.java 加了 @Param 注解,在 mapper.xml 使用方法如下: ``` <select id="selectUser" resultType="User"> SELECT * FROM USER WHERE username = #{username} </select> ``` 可以替换为: ``` <select id="selectUser" resultType="User"> SELECT * FROM USER WHERE username = #{param1.username} </select> ``` 其,"param1" 即为 @Param 注解的参数名称。 ### 回答2: 在Mapper.xml,需要使用`<bind>`标签指定参数的取值,然后在SQL语句使用取值的参数。 例如,在Mapper.java,我们可以使用如下的注解来定义参数: ```java public List<User> getUsersByNameAndGender(@Param("name") String name, @Param("gender") String gender); ``` 在Mapper.xml,我们需要使用`<bind>`标签给参数进行绑定,然后在SQL语句使用被绑定的参数。 例如: ```xml <select id="getUsersByNameAndGender" resultType="User"> <bind name="name" value="@Param('name')" /> <bind name="gender" value="@Param('gender')" /> SELECT * FROM user WHERE name = #{name} AND gender = #{gender} </select> ``` 在上面的示例,`<bind>`标签的`name`属性指定了参数名称,`value`属性指定了参数的取值。然后在SQL语句,我们可以使用这些被绑定的参数来构建查询条件。 这样,当在Java代码调用这个方法时,传入的参数被绑定到SQL语句的相应位置,实现参数传递和动态SQL构建的功能。 ### 回答3: 在mapper.xml使用@Param注解将对应的参数传递到SQL语句。具体写法如下: 1. 假设在mapper.java的方法使用了@Param注解,例如: ```java public List<User> getUserByAgeAndGender(@Param("age") int age, @Param("gender") String gender); ``` 2. 对应的mapper.xml的SQL语句可以使用${}获取@Param注解指定的参数名。例如: ```xml <select id="getUserByAgeAndGender" resultType="user"> SELECT * FROM users WHERE age = ${age} AND gender = #{gender} </select> ``` 这里使用${}获取@Param注解的参数age,并使用#{gender}获取@Param注解的参数gender。 需要注意的是,使用${}时将参数直接替换到SQL语句,可能存在SQL注入的风险。因此,如果参数是动态拼接SQL语句的一部分,建议使用#{}进行参数解析,如上例的gender参数。 上述写法可以实现将mapper.java的参数传递到mapper.xml对应的SQL语句。这样可以灵活地传递多个参数,并且提高代码的可读性和维护性。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值