記一次配置org.mybatis.spring.mapper.MapperScannerConfigurer出現(xiàn)的問(wèn)題

在項(xiàng)目中原始的配置如下:

<?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);
    }
}

現(xiàn)在突然想增加一個(gè)分頁(yè)的插件,修改的代碼如下:

<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">
                    <!--使用下面的方式配置參數(shù),一行配置一個(gè) -->
                    <value>
                        dialect=mysql
                    </value>
                </property>
            </bean>
        </array>
    </property>
</bean>

不想修改原來(lái)的代碼,想讓兩種配置方式都能正常運(yùn)行,所以增加了一個(gè)自動(dòng)掃描mapper的配置,如下:

<!--配置sqlMap 文件路徑,進(jìn)行自動(dòng)掃描加載 -->
<bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
    <property name="basePackage" value="com.test.dao.school"/>
    <property name="sqlSessionFactoryBeanName" value="sqlSessionFactory"/>
</bean>

結(jié)果,導(dǎo)致了問(wèn)題一,如下:


使用版本如下:
mybatis-spring-1.2.0.jar
mybatis-3.2.2.jar

問(wèn)題:
在spring里使用org.mybatis.spring.mapper.MapperScannerConfigurer 進(jìn)行自動(dòng)掃描的時(shí)候,設(shè)置了sqlSessionFactory 的話,他會(huì)優(yōu)先于PropertyPlaceholderConfigurer執(zhí)行,從而導(dǎo)致PropertyPlaceholderConfigurer失效,這時(shí)在xml中用${jdbc.url}、${jdbc.username}、${password}等這樣之類(lèi)的表達(dá)式,將無(wú)法獲取到properties文件里的內(nèi)容。

處理方式:

<!-- 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 文件路徑,進(jìn)行自動(dòng)掃描加載 -->
<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 文件路徑,進(jìn)行自動(dòng)掃描加載 -->
<bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
    <property name="basePackage" value="com.test.dao.school"/>
    <property name="sqlSessionFactoryBeanName" value="mybatisSqlSessionFactory"/>
</bean>

原因:
使用sqlSessionFactoryBeanName注入,不會(huì)立即初始化sqlSessionFactory, 所以不會(huì)引發(fā)提前初始化問(wèn)題,同時(shí)還應(yīng)注意在配置org.mybatis.spring.SqlSessionFactoryBean這個(gè)Bean時(shí),id不能為sqlSessionFactory,如果為這樣的話會(huì)導(dǎo)致MapperScannerConigurer在bean定義加載時(shí),加載PropertyPlaceholderConfigurer還沒(méi)來(lái)得及替換定義中的變量

還有一種方式將mybatis-spring的版本換成1.0.0不會(huì)出現(xiàn)加載順序的問(wèn)題,但本人沒(méi)有測(cè)試。

改完之后,引出了問(wèn)題二,如下:



問(wèn)題:
SqlSessionDaoSupport在注入SqlSessionFactory 和 SqlSessionTemplate時(shí)失敗了,拋出了這個(gè)異常:

protected void checkDaoConfig() {
    notNull(this.sqlSession, "Property 'sqlSessionFactory' or 'sqlSessionTemplate' are required");
}

解決方式:
寫(xiě)一個(gè)基類(lèi)繼承SqlSessionDaoSupport,然后讓繼承SqlSessionDaoSupport 的dao層都繼承BaseDao,這樣手動(dòng)注入一個(gè)SqlSessionFactory

public class BaseDao extends SqlSessionDaoSupport {
    @Resource
    public void setSqlSessionFactory(SqlSessionFactory sqlSessionFactory){
        super.setSqlSessionFactory(sqlSessionFactory);
    }
}

原因:
mybatis-spring-1.2.0中取消了自動(dòng)注入SqlSessionFactory 和 SqlSessionTemplate,所以導(dǎo)致不能自動(dòng)注入進(jìn)來(lái)。
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;
    }
    ……
}

現(xiàn)在有一個(gè)問(wèn)題有些困擾我,BaseDao基類(lèi)中,用@Resource注入SqlSessionFactory,但我在配置文件中配置的id=“mybatisSqlSessionFactory”,為什么可以注入進(jìn)來(lái)?希望各位大大能幫忙解答。

最終程序成功的跑起來(lái)了。本人第一次寫(xiě)博客,有問(wèn)題歡迎各位大大指正。

參考文章:
https://blog.csdn.net/huiwenjie168/article/details/51722290
https://www.cnblogs.com/hawk0035/p/3337283.html?utm_source=tuicool

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • 單獨(dú)使用mybatis是有很多限制的(比如無(wú)法實(shí)現(xiàn)跨越多個(gè)session的事務(wù)),而且很多業(yè)務(wù)系統(tǒng)本來(lái)就是使用sp...
    七寸知架構(gòu)閱讀 3,578評(píng)論 0 53
  • Spring Cloud為開(kāi)發(fā)人員提供了快速構(gòu)建分布式系統(tǒng)中一些常見(jiàn)模式的工具(例如配置管理,服務(wù)發(fā)現(xiàn),斷路器,智...
    卡卡羅2017閱讀 136,506評(píng)論 19 139
  • 1. 簡(jiǎn)介 1.1 什么是 MyBatis ? MyBatis 是支持定制化 SQL、存儲(chǔ)過(guò)程以及高級(jí)映射的優(yōu)秀的...
    笨鳥(niǎo)慢飛閱讀 6,219評(píng)論 0 4
  • Spring 技術(shù)筆記Day 1 預(yù)熱知識(shí)一、 基本術(shù)語(yǔ)Blob類(lèi)型,二進(jìn)制對(duì)象Object Graph:對(duì)象圖...
    OchardBird閱讀 1,074評(píng)論 0 2
  • # 前言 在前兩篇文章我們?cè)?mybatis 源碼中探究了他的運(yùn)行原理,但在實(shí)際使用中,我們需要將其和Spring...
    莫那一魯?shù)?/span>閱讀 3,586評(píng)論 0 4

友情鏈接更多精彩內(nèi)容