记一次配置org.mybatis.spring.mapper.M
在项目中原始的配置如下:
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:aop="http://www.springframework.org/schema/aop"
xmlns:tx="http://www.springframework.org/schema/tx"
xmlns:util="http://www.springframework.org/schema/util"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/tx
http://www.springframework.org/schema/tx/spring-tx.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop.xsd
http://www.springframework.org/schema/util
http://www.springframework.org/schema/util/spring-util.xsd"
default-autowire="byName">
<bean id="baseDataSource" class="org.apache.commons.dbcp.BasicDataSource" abstract="true" destroy-method="close" lazy-init="true">
<property name="driverClassName" value="${jdbc.driver}" />
<property name="username" value="${jdbc.username}" />
<property name="password" value="${jdbc.password}" />
<property name="maxActive" value="30" />
<property name="initialSize" value="3" />
<property name="timeBetweenEvictionRunsMillis" value="290000" />
<property name="minEvictableIdleTimeMillis" value="290000" />
<property name="numTestsPerEvictionRun" value="20" />
</bean>
<!-- DBCP config -->
<bean id="targetDataSource" parent="baseDataSource" lazy-init="true">
<property name="url" value="${master.jdbc.url}" />
</bean>
<bean id="slaveDataSource" parent="baseDataSource" lazy-init="true">
<property name="url" value="${slave.jdbc.url}"/>
</bean>
<bean id="dataSource" class="org.springframework.jdbc.datasource.LazyConnectionDataSourceProxy">
<property name="targetDataSource" ref="targetDataSource" />
</bean>
<bean id="dataSourceSlave" class="org.springframework.jdbc.datasource.LazyConnectionDataSourceProxy">
<property name="targetDataSource" ref="slaveDataSource"/>
</bean>
<bean id="dataSource" class="com.jd.gx.dao.utils.DynamicDataSource">
<property name="targetDataSources">
<util:map key-type="java.lang.String">
<entry key="master" value-ref="dataSource" />
<entry key="slave" value-ref="dataSourceSlave"/>
</util:map>
</property>
<property name="defaultTargetDataSource" ref="dataSource" />
<!--<property name="dbInUse" value="master" />-->
</bean>
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource">
<ref bean="dataSource" />
</property>
</bean>
<tx:annotation-driven transaction-manager="transactionManager" />
<tx:advice id="txAdvice" transaction-manager="transactionManager">
<tx:attributes>
<tx:method name="*" propagation="REQUIRED" />
</tx:attributes>
</tx:advice>
<aop:config proxy-target-class="true">
<aop:pointcut id="txServiceMethods" expression="execution(* com.*.service..*(..))" />
<aop:advisor advice-ref="txAdvice" pointcut-ref="txServiceMethods" />
</aop:config>
<!-- mybatis config -->
<bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
<property name="dataSource" ref="dataSource" />
<property name="configLocation" value="classpath:sqlMapConfig.xml" />
<property name="mapperLocations" value="classpath*:sqlmap/**/*.xml" />
</bean>
<bean id="sqlSession" class="org.mybatis.spring.SqlSessionTemplate">
<constructor-arg index="0" ref="sqlSessionFactory"/>
</bean>
<bean id="selectDbAdvice" class="com.test.dao.utils.DbSelectAdvice">
<property name="methodKey">
<list>
<value>count</value>
<value>select</value>
</list>
</property>
<property name="showLog" value="false"/>
</bean>
<aop:aspectj-autoproxy/>
<aop:config>
<aop:pointcut expression="execution(* com.test.dao..*.*(..))" id="cutPoint"/>
<aop:advisor advice-ref="selectDbAdvice" pointcut-ref="cutPoint"/>
</aop:config>
</beans>
接口使用如下配置方式:
@Component
public class UserDaoImpl extends SqlSessionDaoSupport implements UserDao {
@Override
public int insertUserInfo(UserInfo userInfo) {
return this.getSqlSession().insert("Order.insertUserInfo", userInfo);
}
}
现在突然想增加一个分页的插件,修改的代码如下:
<bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
<property name="dataSource" ref="dataSource" />
<property name="configLocation" value="classpath:sqlMapConfig.xml" />
<property name="mapperLocations" value="classpath*:sqlmap/**/*.xml" />
<property name="plugins">
<array>
<bean class="com.test.dao.PerformanceInterceptor">
<property name="openTimeLog" value="true"/>
</bean>
<!-- 新增的 -->
<bean class="com.github.pagehelper.PageHelper">
<property name="properties">
<!--使用下面的方式配置参数,一行配置一个 -->
<value>
dialect=mysql
</value>
</property>
</bean>
</array>
</property>
</bean>
不想修改原来的代码,想让两种配置方式都能正常运行,所以增加了一个自动扫描mapper的配置,如下:
<!--配置sqlMap 文件路径,进行自动扫描加载 -->
<bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
<property name="basePackage" value="com.test.dao.school"/>
<property name="sqlSessionFactoryBeanName" value="sqlSessionFactory"/>
</bean>
结果,导致了问题一,如下:
使用版本如下:
mybatis-spring-1.2.0.jar
mybatis-3.2.2.jar
问题:
在spring里使用org.mybatis.spring.mapper.MapperScannerConfigurer 进行自动扫描的时候,设置了sqlSessionFactory 的话,他会优先于PropertyPlaceholderConfigurer执行,从而导致PropertyPlaceholderConfigurer失效,这时在xml中用${jdbc.url}、${jdbc.username}、${password}等这样之类的表达式,将无法获取到properties文件里的内容。
处理方式:
将
<!-- mybatis config -->
<bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
<property name="dataSource" ref="dataSource" />
<property name="configLocation" value="classpath:sqlMapConfig.xml" />
<property name="mapperLocations" value="classpath*:sqlmap/**/*.xml" />
</bean>
<!--配置sqlMap 文件路径,进行自动扫描加载 -->
<bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
<property name="basePackage" value="com.test.dao.school"/>
<property name="sqlSessionFactoryBeanName" value="sqlSession"/>
</bean>
修改为
<!-- mybatis config -->
<bean id="mybatisSqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
<property name="dataSource" ref="dataSource" />
<property name="configLocation" value="classpath:sqlMapConfig.xml" />
<property name="mapperLocations" value="classpath*:sqlmap/**/*.xml" />
</bean>
<!--配置sqlMap 文件路径,进行自动扫描加载 -->
<bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
<property name="basePackage" value="com.test.dao.school"/>
<property name="sqlSessionFactoryBeanName" value="mybatisSqlSessionFactory"/>
</bean>
原因:
使用sqlSessionFactoryBeanName注入,不会立即初始化sqlSessionFactory, 所以不会引发提前初始化问题,同时还应注意在配置org.mybatis.spring.SqlSessionFactoryBean这个Bean时,id不能为sqlSessionFactory,如果为这样的话会导致MapperScannerConigurer在bean定义加载时,加载PropertyPlaceholderConfigurer还没来得及替换定义中的变量
还有一种方式将mybatis-spring的版本换成1.0.0不会出现加载顺序的问题,但本人没有测试。
改完之后,引出了问题二,如下:
问题:
SqlSessionDaoSupport在注入SqlSessionFactory 和 SqlSessionTemplate时失败了,抛出了这个异常:
protected void checkDaoConfig() {
notNull(this.sqlSession, "Property 'sqlSessionFactory' or 'sqlSessionTemplate' are required");
}
解决方式:
写一个基类继承SqlSessionDaoSupport,然后让继承SqlSessionDaoSupport 的dao层都继承BaseDao,这样手动注入一个SqlSessionFactory
public class BaseDao extends SqlSessionDaoSupport {
@Resource
public void setSqlSessionFactory(SqlSessionFactory sqlSessionFactory){
super.setSqlSessionFactory(sqlSessionFactory);
}
}
原因:
mybatis-spring-1.2.0中取消了自动注入SqlSessionFactory 和 SqlSessionTemplate,所以导致不能自动注入进来。
1.2.0的源码如下:
/**
* Convenient super class for MyBatis SqlSession data access objects.
* It gives you access to the template which can then be used to execute SQL methods.
* <p>
* This class needs a SqlSessionTemplate or a SqlSessionFactory.
* If both are set the SqlSessionFactory will be ignored.
* <p>
* {code Autowired} was removed from setSqlSessionTemplate and setSqlSessionFactory
* in version 1.2.0.
*
* @see #setSqlSessionFactory
* @see #setSqlSessionTemplate
* @see SqlSessionTemplate
* @version $Id$
*/
public abstract class SqlSessionDaoSupport extends DaoSupport {
private SqlSession sqlSession;
private boolean externalSqlSession;
public void setSqlSessionFactory(SqlSessionFactory sqlSessionFactory) {
if (!this.externalSqlSession) {
this.sqlSession = new SqlSessionTemplate(sqlSessionFactory);
}
}
public void setSqlSessionTemplate(SqlSessionTemplate sqlSessionTemplate) {
this.sqlSession = sqlSessionTemplate;
this.externalSqlSession = true;
}
……
}
1.1.0源码如下:
public abstract class SqlSessionDaoSupport extends DaoSupport {
private SqlSession sqlSession;
private boolean externalSqlSession;
@Autowired(required = false)
public final void setSqlSessionFactory(SqlSessionFactory sqlSessionFactory) {
if (!this.externalSqlSession) {
this.sqlSession = new SqlSessionTemplate(sqlSessionFactory);
}
}
@Autowired(required = false)
public final void setSqlSessionTemplate(SqlSessionTemplate sqlSessionTemplate) {
this.sqlSession = sqlSessionTemplate;
this.externalSqlSession = true;
}
……
}
现在有一个问题有些困扰我,BaseDao基类中,用@Resource注入SqlSessionFactory,但我在配置文件中配置的id=“mybatisSqlSessionFactory”,为什么可以注入进来?希望各位大大能帮忙解答。
最终程序成功的跑起来了。本人第一次写博客,有问题欢迎各位大大指正。
参考文章:
https://blog.csdn.net/huiwenjie168/article/details/51722290
https://www.cnblogs.com/hawk0035/p/3337283.html?utm_source=tuicool