MyBatis和Spring設定callSettersOnNulls

renfufei的專欄發表於2014-09-28

專案中整合Mybatis與Spring,使用的是Mybatis3.2.7,以及Spring4.0.5,mybatis-spring-1.2.2;
因為專案組成員想要偷懶,將資料從DB中查詢出來時需要將欄位對映為Map,而不想封裝成Bean.

預設情況下,Mybatis對Map的解析生成, 如果值(value)為null的話,那麼key也不會被加入到map中.
於是對Map遍歷時,key就遍歷不到,因為前端工具的需要,必須有這個key,網上搜尋後發現需要設定callSettersOnNulls 這個屬性.
那就設定唄, 在 sqlSessionFactory 的定義中,指定 configLocation 屬性,指向另一個檔案,如下所示

檔案清單: mybatis-env-setting.xml

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE configuration 
    PUBLIC "-//mybatis.org//DTD Config 3.0//EN" 
    "http://mybatis.org/dtd/mybatis-3-config.dtd"> 

<!-- 
	如果內網機器報錯,請使用下面這種笨辦法
 -->
<!-- 
<!DOCTYPE configuration
        PUBLIC "-//www.mybatis.org//DTD Config 3.0//EN"
        "E:/bao/tomcat/apache-tomcat-6.0.14/webapps/pmsys/WEB-INF/classes/mybatis/mybatis-3-config.dtd">
 -->

<configuration>
	<settings>
	  <!-- 只設定需要的,其他使用預設值 -->
	  <!-- 開啟快取,預設就是開啟的,2層開關,需要在Mapper檔案中也指定 cache 標籤才會真正使用快取 -->
	  <setting name="cacheEnabled" value="true"/>
	  <!-- 在null時也呼叫 setter,適應於返回Map,3.2版本以上可用 -->
	    <setting name="callSettersOnNulls" value="true"/>
	</settings>
</configuration>

然後使用,一切正常,OK.

過了幾天, 實施專案時出BUG了, 因為是企業內網伺服器,不能訪問 mybatis.org,於是啟動出錯.
【Mybatis 這個渣渣,在啟動時會去獲取並校驗DTD,目前還不知道在哪裡配置讓其不進行校驗.】
網上搜尋半天,沒有好的解決辦法, 看到有方法說將dtd下載到本地,然後直接指定路徑,就像上面註釋掉的那部分一樣。

問題也算是解決了,可是很土,而且各個機器不一定都有同樣的目錄,這種掉渣的方法肯定會遭人詬病的。
於是百度谷歌又搜尋了半天,沒找到辦法,根本沒有人提這茬。

於是想著自己翻原始碼看看:

public class SqlSessionFactoryBean 
    implements FactoryBean<SqlSessionFactory>, InitializingBean, 
    ApplicationListener<ApplicationEvent> {

  private static final Log logger = LogFactory.getLog(SqlSessionFactoryBean.class);
  // 這裡可以配置configLocation資源
  private Resource configLocation;

  private Resource[] mapperLocations;

  private DataSource dataSource;

  private TransactionFactory transactionFactory;
  // 這裡可以配置configurationProperties屬性
  private Properties configurationProperties;

  ......

  protected SqlSessionFactory buildSqlSessionFactory() throws IOException {

    Configuration configuration;

    XMLConfigBuilder xmlConfigBuilder = null;
    // 先查詢 configLocation 屬性
    if (this.configLocation != null) {
      xmlConfigBuilder = new XMLConfigBuilder(this.configLocation.getInputStream(), null, this.configurationProperties);
      configuration = xmlConfigBuilder.getConfiguration();
    } else {
      if (logger.isDebugEnabled()) {
        logger.debug("Property 'configLocation' not specified, using default MyBatis Configuration");
      }
      // 如果找不到configLocation,就只使用 configurationProperties
      configuration = new Configuration();
      configuration.setVariables(this.configurationProperties);
    }

    ......

看到了 configurationProperties 這個屬性,可是 該怎麼設定呢,總算找到了一篇很靠譜的學習筆記: Spring的Bean之設定Bean值

於是,抄襲之,自己設定了一下相應的屬性

形成的配置檔案片段如下所示:

<!-- myBatis配置 -->
<bean id="sqlSessionFactory">
	<property name="dataSource" ref="dataSource" />

	<!-- 表示在mybatis.mapping包或以下所有目錄中,以 Mapper.xml結尾所有檔案 -->
	<property name="mapperLocations">
		<value>classpath:com/cncounter/dao/oracle/**/*Mapper.xml</value>
		<!-- 
		<list>
			<value>classpath:com/cncounter/dao/oracle/res/*Mapper.xml</value>
			<value>classpath:com/cncounter/dao/oracle/user/*Mapper.xml</value>
		</list>
		 -->
	</property>
	<!-- 
	<property name="configLocation">
		<value>classpath:mybatis/mybatis-env-setting.xml</value>
	</property>
	 -->
	<!--  切換一種方式,不配置configLocation  -->
	<property name="configurationProperties">
		<props>
			<prop key="cacheEnabled">true</prop>
			<prop key="callSettersOnNulls">true</prop>
		</props>
	</property>
</bean>

啟動沒報錯,但是還沒檢驗.應該沒多大問題…

相關文章