項目中集成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>
-
-
- <setting name="cacheEnabled" value="true"/>
-
- <setting name="callSettersOnNulls" value="true"/>
- </settings>
- </configuration>
<?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);
-
- private Resource configLocation;
-
- private Resource[] mapperLocations;
-
- private DataSource dataSource;
-
- private TransactionFactory transactionFactory;
-
- private Properties configurationProperties;
-
- ......
-
- protected SqlSessionFactory buildSqlSessionFactory() throws IOException {
-
- Configuration configuration;
-
- XMLConfigBuilder xmlConfigBuilder = null;
-
- 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");
- }
-
- configuration = new Configuration();
- configuration.setVariables(this.configurationProperties);
- }
-
- ......
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);
}
......</pre><br>看到了 <strong>configurationProperties</strong> 這個屬性,可是 該怎么設置呢,總算找到了一篇很靠譜的學習筆記: <a target="_blank" href="http://www.cnblogs.com/chenssy/archive/2013/03/17/2964593.html">Spring的Bean之設置Bean值</a><br><br>於是,抄襲之,自己設置了一下相應的屬性<br><br>形成的配置文件片段如下所示:<br><div class="dp-highlighter bg_html"><div class="bar"><div class="tools"><b>[html]</b> <a href="#" class="ViewSource" title="view plain" onclick="dp.sh.Toolbar.Command('ViewSource',this);return false;" target="_blank">view plain</a><span data-mod="popu_168"> <a href="#" class="CopyToClipboard" title="copy" onclick="dp.sh.Toolbar.Command('CopyToClipboard',this);return false;" target="_blank">copy</a><div style="position: absolute; left: 486px; top: 2558px; width: 18px; height: 18px; z-index: 99;"><embed id="ZeroClipboardMovie_3" src="http://static.blog.csdn.net/scripts/ZeroClipboard/ZeroClipboard.swf" loop="false" menu="false" quality="best" bgcolor="#ffffff" width="18" height="18" name="ZeroClipboardMovie_3" align="middle" allowscriptaccess="always" allowfullscreen="false" type="application/x-shockwave-flash" pluginspage="http://www.macromedia.com/go/getflashplayer" flashvars="id=3&width=18&height=18" wmode="transparent"></div></span><span data-mod="popu_169"> <a href="#" class="PrintSource" title="print" onclick="dp.sh.Toolbar.Command('PrintSource',this);return false;" target="_blank">print</a></span><a href="#" class="About" title="?" onclick="dp.sh.Toolbar.Command('About',this);return false;" target="_blank">?</a></div></div><ol start="1" class="dp-xml"><li class="alt"><span><span class="comments"><!-- myBatis配置 --></span><span> </span></span></li><li class=""><span><span class="tag"><</span><span class="tag-name">bean</span><span> </span><span class="attribute">id</span><span>=</span><span class="attribute-value">"sqlSessionFactory"</span><span> </span><span class="attribute">class</span><span>=</span><span class="attribute-value">"org.mybatis.spring.SqlSessionFactoryBean"</span><span class="tag">></span><span> </span></span></li><li class="alt"><span> <span class="tag"><</span><span class="tag-name">property</span><span> </span><span class="attribute">name</span><span>=</span><span class="attribute-value">"dataSource"</span><span> </span><span class="attribute">ref</span><span>=</span><span class="attribute-value">"dataSource"</span><span> </span><span class="tag">/></span><span> </span></span></li><li class=""><span> </span></li><li class="alt"><span> <span class="comments"><!-- 表示在mybatis.mapping包或以下所有目錄中,以 Mapper.xml結尾所有文件 --></span><span> </span></span></li><li class=""><span> <span class="tag"><</span><span class="tag-name">property</span><span> </span><span class="attribute">name</span><span>=</span><span class="attribute-value">"mapperLocations"</span><span class="tag">></span><span> </span></span></li><li class="alt"><span> <span class="tag"><</span><span class="tag-name">value</span><span class="tag">></span><span>classpath:com/cncounter/dao/oracle/**/*Mapper.xml</span><span class="tag"></</span><span class="tag-name">value</span><span class="tag">></span><span> </span></span></li><li class=""><span> <!-- </span></li><li class="alt"><span> <span class="tag"><</span><span class="tag-name">list</span><span class="tag">></span><span> </span></span></li><li class=""><span> <span class="tag"><</span><span class="tag-name">value</span><span class="tag">></span><span>classpath:com/cncounter/dao/oracle/res/*Mapper.xml</span><span class="tag"></</span><span class="tag-name">value</span><span class="tag">></span><span> </span></span></li><li class="alt"><span> <span class="tag"><</span><span class="tag-name">value</span><span class="tag">></span><span>classpath:com/cncounter/dao/oracle/user/*Mapper.xml</span><span class="tag"></</span><span class="tag-name">value</span><span class="tag">></span><span> </span></span></li><li class=""><span> <span class="tag"></</span><span class="tag-name">list</span><span class="tag">></span><span> </span></span></li><li class="alt"><span> --<span class="tag">></span><span> </span></span></li><li class=""><span> <span class="tag"></</span><span class="tag-name">property</span><span class="tag">></span><span> </span></span></li><li class="alt"><span> <!-- </span></li><li class=""><span> <span class="tag"><</span><span class="tag-name">property</span><span> </span><span class="attribute">name</span><span>=</span><span class="attribute-value">"configLocation"</span><span class="tag">></span><span> </span></span></li><li class="alt"><span> <span class="tag"><</span><span class="tag-name">value</span><span class="tag">></span><span>classpath:mybatis/mybatis-env-setting.xml</span><span class="tag"></</span><span class="tag-name">value</span><span class="tag">></span><span> </span></span></li><li class=""><span> <span class="tag"></</span><span class="tag-name">property</span><span class="tag">></span><span> </span></span></li><li class="alt"><span> --<span class="tag">></span><span> </span></span></li><li class=""><span> <span class="comments"><!-- 切換一種方式,不配置configLocation --></span><span> </span></span></li><li class="alt"><span> <span class="tag"><</span><span class="tag-name">property</span><span> </span><span class="attribute">name</span><span>=</span><span class="attribute-value">"configurationProperties"</span><span class="tag">></span><span> </span></span></li><li class=""><span> <span class="tag"><</span><span class="tag-name">props</span><span class="tag">></span><span> </span></span></li><li class="alt"><span> <span class="tag"><</span><span class="tag-name">prop</span><span> </span><span class="attribute">key</span><span>=</span><span class="attribute-value">"cacheEnabled"</span><span class="tag">></span><span>true</span><span class="tag"></</span><span class="tag-name">prop</span><span class="tag">></span><span> </span></span></li><li class=""><span> <span class="tag"><</span><span class="tag-name">prop</span><span> </span><span class="attribute">key</span><span>=</span><span class="attribute-value">"callSettersOnNulls"</span><span class="tag">></span><span>true</span><span class="tag"></</span><span class="tag-name">prop</span><span class="tag">></span><span> </span></span></li><li class="alt"><span> <span class="tag"></</span><span class="tag-name">props</span><span class="tag">></span><span> </span></span></li><li class=""><span> <span class="tag"></</span><span class="tag-name">property</span><span class="tag">></span><span> </span></span></li><li class="alt"><span><span class="tag"></</span><span class="tag-name">bean</span><span class="tag">></span><span> </span></span></li></ol></div><pre code_snippet_id="477551" snippet_file_name="blog_20140929_3_1402113" name="code" class="html" style="display: none;"><!-- myBatis配置 -->
<bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
<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>
啟動沒報錯,但是還沒檢驗.應該沒多大問題...
補充: 還是不起作用,於是沒法子了,只好拆開Mybatis的源碼,找到類 org.apache.ibatis.session.Configuration ,然后,在自己的目錄下把源碼拷出來, 自己在test目錄建一個包,建一個類,和Configuration一模一樣,然后修改 callSettersOnNulls 的默認值為 true,然后找到編譯好的3個class文件(有內部類),替換到mybatis-3.2.7.jar中去,OK,成功解決。
按理說應該是編譯整個mybatis的,但是maven有點坑,目前還不想這樣做
看了 mybatis高級應用系列一:分頁功能 這篇文章,發覺冤枉 MyBatis了,其實是 Mybatis-Spring挖下的坑, 校驗的時候不走Mybatis的默認通道, 而是自己解析了對應的XML文件,還要去網上搜索dtd文件,巨坑無比啊.
給了 configurationProperties 這么個選項,卻不使用,真是不好。
附上一篇, 如何解決Spring附加組件中dtd的這種坑