项目中集成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的这种坑