Java&JAVA EE

记一次配置org.mybatis.spring.mapper.M

2018-05-09  本文已影响171人  田里跑出来的鼹鼠

在项目中原始的配置如下:

<?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

上一篇下一篇

猜你喜欢

热点阅读