在使用mybatis时,经常的写法即使用下面的*写法,这种方法最简单,不用复杂的resultMap.如下所示:
select * from table where condition
在这种写法下,要求一定很严格,即在相应的domain中的属性字段必须和数据库中的字段相一致,否则即不能进行匹配。如果在数据库中,有一个字段为a_id,那么在domain中的属性也必须这样写,写成a_id,这种代码编写方式肯定不符合代码规范。
针对这种情况,在mybatis中就提出一个匹配变量mapUnderscoreToCamelCase,即在碰到有下划线的时候,自动转化为驼峰式的方式。但是这个变量有一个问题,即它会强制进行转换。当我们的domain即有a_id,又有aId的编写方式时,这个变量就一点作用也没有,并且如果进行配置了,还会造成程序出错。
还有一种需求就是,如果我们的domain先于数据库产生,当最终的数据库产生时,需要一种类似在hibernate中的column mapping的需求产生,即数据库中指定字段匹配domain中的指定属性。
经过程序中进行查找,我们发现最终的结果匹配过程是由类FastResultSetHandler来完成的,而在这个实现中,针对在上面的处理过程,是由方法applyAutomaticMappings来完成的。它的方法签名是protected,那么我们是否可以通过继承这个类,然后重写这个方法呢。答案是否定的,因为这个类的初始化已经固化在类Configuration中了,即我们有了实现类,但是mybatis始终不会实现化我们所要求的类。并且,在过程中,mybatis的插件模式即plugin也没有办法,因为类fastResultSetHandler的接口ResultSetHandler只有2个方法,但是整个实现类中有N个方法,我们不可能将所有的方法都重新写一次。
接下来最终的方法就只有一个,即在之前我们所使用的,代码替换。我们需要一个类直接将其实现替换即可。
这里就不再仔细描述如何进行替换,可以参考这篇文章:http://www.iflym.com/index.php/code/use-javassist-to-modify-java-object-method.html
这里直接贴实现:
protected boolean applyAutomaticMappings(ResultSet rs, List<String> unmappedColumnNames, MetaObject metaObject, String columnPrefix, ResultColumnCache resultColumnCache) throws SQLException { boolean foundValues = false; for(String columnName : unmappedColumnNames) { String propertyName = columnName; if(columnPrefix != null && columnPrefix.length() > 0) { if(columnName.startsWith(columnPrefix)) { propertyName = columnName.substring(columnPrefix.length()); } else { continue; } } boolean mapUnderscoreToCamelCase = configuration.isMapUnderscoreToCamelCase(); String property = metaObject.findProperty(propertyName, mapUnderscoreToCamelCase); //如果找不到,则首先查找columnMap if(property == null) { Class sourceClass = metaObject.getOriginalObject().getClass(); property = com.appcenter.cp.component.mybatis.DomainColumnMapper.getDomainColumnMapping(sourceClass) .get(propertyName.toLowerCase()); } //最后尝试去下划线匹配 if(property == null && !mapUnderscoreToCamelCase) { property = metaObject.findProperty(propertyName, true); } if(property != null) { final Class propertyType = metaObject.getSetterType(property); if(typeHandlerRegistry.hasTypeHandler(propertyType)) { final TypeHandler typeHandler = resultColumnCache.getTypeHandler(propertyType, columnName); final Object value = typeHandler.getResult(rs, columnName); if(value != null) { metaObject.setValue(property, value); foundValues = true; } } } } return foundValues; }
在这个实现中,我们只需要将我们所需要的代码加入到合适的地方即可。然后通过方法替换即可实现相应的功能。当然,直接copy上面的代码是不行的,你会方法,在方法所使用的变量以及参数,都是protected类型的,不可直接使用,实际上也很简单,我们只需要继承原fastResultSetHandler即可,随便弄个构造函数。因为我们不需要这些,只是需要这个方法实现而已。
在具体替换过程中,可能会碰到类似 invalid length 251 in localAttributeTable之类的错误。这个错误只需要升级一下工程中的javassist.jar即可,笔者使用的为3.17.1版本。
mybatis版本为3.1.1
转载请标明出处:i flym
本文地址:https://www.iflym.com/index.php/code/201303210001.html