MyBatis 3.3.1 在resultMap中使用association但是没有指定id时的结果集bug
2016-04-15 02:56
573 查看
情景描述:
resultMap中,如果不指定id列,在映射中同时存在result 和association,如果表中映射过的字段 有连续的非空重复值,那么存在重复值的行不会被加入结果集中。
JavaBean(省略getter setter):
Mapper:
SQL:
select * from t_account;
在数据库中的查询结果(部分):
1、图中涂红的部分修改过,原来的值与上一行相同,都是 00:00:00。
2、修改以前,程序查询结果中只有id<=38的数据,因为id=37行(以下简称37行)与36行的opt_time字段不同,38行与37行的create_time、update_time字段不同,而39行与38行的这三个映射字段的值完全相同
3、修改后,查询结果中39、40行能显示了,其后的数据不能显示
4、在Mapper中加入id列设置后,所有数据行都能显示了。
建议:在所有的resultMap定义中,最好都指明id列,避免出现类似情况。
追查问题的过程受以下文章启发:
1.MyBatis使用Collection查询多对多或一对多结果集bug
http://www.cnblogs.com/zemliu/archive/2013/08/16/3263053.html
2.mybatis核心组件详解——ResultSetHandler
http://my.oschina.net/lixin91/blog/624772
handleRowValuesForNestedResultMap方法
private void handleRowValuesForNestedResultMap(ResultSetWrapper rsw,
ResultMap resultMap,
ResultHandler<?> resultHandler,
RowBounds rowBounds,
ResultMapping parentMapping) throwsSQLException
{
final DefaultResultContext <Object> resultContext = new DefaultResultContext<Object>();
skipRows(rsw.getResultSet(), rowBounds);
Object rowValue = null;
while (shouldProcessMoreRows( resultContext, rowBounds )
&& rsw.getResultSet().next())
{
final ResultMap discriminatedResultMap =
resolveDiscriminatedResultMap(rsw.getResultSet(),resultMap , null);
// 根据映射字段的值生成缓存key
final CacheKey rowKey =
createRowKey(discriminatedResultMap, rsw, null);
// 在缓存中查询key
Object partialObject = nestedResultObjects.get( rowKey);
// issue
#577 && #542
if (mappedStatement.isResultOrdered())
{
if (partialObject == null && rowValue != null)
{
nestedResultObjects.clear();
storeObject( resultHandler, resultContext, rowValue, parentMapping, rsw.getResultSet());
}
rowValue =
getRowValue( rsw, discriminatedResultMap, rowKey, null, partialObject);
} else {
// 在getRowValue方法中,如果存在缓存就直接取值了
rowValue =
getRowValue( rsw, discriminatedResultMap, rowKey, null, partialObject);
if (partialObject == null)
{
storeObject( resultHandler, resultContext, rowValue, parentMapping, rsw.getResultSet());
}
}
}
if (rowValue != null && mappedStatement.isResultOrdered()
&& shouldProcessMoreRows(resultContext, rowBounds ))
{
storeObject(resultHandler, resultContext, rowValue, parentMapping, rsw.getResultSet());
}
}
getRowValue方法:
private Object
getRowValue(ResultSetWrapper rsw,
ResultMap resultMap,
CacheKey combinedKey,
String columnPrefix,
Object partialObject) throws SQLException
{
final String resultMapId = resultMap.getId();
Object resultObject = partialObject;
if (resultObject != null)
{
final MetaObject metaObject = configuration.newMetaObject( resultObject);
putAncestor(resultObject, resultMapId, columnPrefix);
applyNestedResultMappings (rsw, resultMap , metaObject , columnPrefix , combinedKey, false);
ancestorObjects.remove( resultMapId);
} else {
final ResultLoaderMap lazyLoader = new ResultLoaderMap();
resultObject =
createResultObject( rsw, resultMap, lazyLoader, columnPrefix);
if (resultObject != null &&
!typeHandlerRegistry.hasTypeHandler(resultMap .getType()))
{
final MetaObject metaObject = configuration.newMetaObject( resultObject);
boolean foundValues =
!resultMap.getConstructorResultMappings().isEmpty();
if (shouldApplyAutomaticMappings( resultMap, true))
{
foundValues =
applyAutomaticMappings( rsw, resultMap, metaObject, columnPrefix)
||foundValues;
}
foundValues =
applyPropertyMappings( rsw, resultMap, metaObject, lazyLoader, columnPrefix)
|| foundValues;
putAncestor( resultObject, resultMapId, columnPrefix);
foundValues = applyNestedResultMappings (rsw, resultMap , metaObject , columnPrefix,combinedKey, true)
|| foundValues;
ancestorObjects.remove( resultMapId);
foundValues = lazyLoader.size()
> 0 || foundValues;
resultObject = foundValues ? resultObject : null;
}
if (combinedKey !=
CacheKey. NULL_CACHE_KEY)
{
nestedResultObjects.put( combinedKey, resultObject);
}
}
return resultObject;
}
resultMap中,如果不指定id列,在映射中同时存在result 和association,如果表中映射过的字段 有连续的非空重复值,那么存在重复值的行不会被加入结果集中。
JavaBean(省略getter setter):
public class Account { /** 属性账目编号 */ private Long id; /** 属性物料编码相关信息 */ private Item item; /** * 属性单据类型 0 出库,1入库 ,9:默认(出现9则是异常) */ private int type = 9; /** 属性数量 */ private Double number; /** 属性归属单位 */ private String department; /** 属性操作员 */ private String operator; /** 属性经办人 */ private String handler; /** 属性出入库原因 */ private String reason; /** 属性出入库时间 */ private Date optTime; /** 属性录入时间 */ private Date createTime = Calendar.getInstance().getTime(); /** 属性最后修改时间 */ private Date updateTime; /** 属性最后修改人 */ private User updater; }
Mapper:
<resultMap type="Account"id="accountMap"autoMapping="true"> <id column ="id" property="id"/> <result column ="opt_time" property="optTime"/> <result column ="create_time" property="createTime"/> <result column ="update_time" property="updateTime"/> <association property ="item" javaType="Item"> <result column ="item_code" property="code"/> <result column ="item_name" property="name"/> <result column ="item_model" property="model"/> <result column ="unit" property="unit"/> </association > </resultMap >
SQL:
select * from t_account;
在数据库中的查询结果(部分):
1、图中涂红的部分修改过,原来的值与上一行相同,都是 00:00:00。
2、修改以前,程序查询结果中只有id<=38的数据,因为id=37行(以下简称37行)与36行的opt_time字段不同,38行与37行的create_time、update_time字段不同,而39行与38行的这三个映射字段的值完全相同
3、修改后,查询结果中39、40行能显示了,其后的数据不能显示
4、在Mapper中加入id列设置后,所有数据行都能显示了。
建议:在所有的resultMap定义中,最好都指明id列,避免出现类似情况。
追查问题的过程受以下文章启发:
1.MyBatis使用Collection查询多对多或一对多结果集bug
http://www.cnblogs.com/zemliu/archive/2013/08/16/3263053.html
2.mybatis核心组件详解——ResultSetHandler
http://my.oschina.net/lixin91/blog/624772
handleRowValuesForNestedResultMap方法
private void handleRowValuesForNestedResultMap(ResultSetWrapper rsw,
ResultMap resultMap,
ResultHandler<?> resultHandler,
RowBounds rowBounds,
ResultMapping parentMapping) throwsSQLException
{
final DefaultResultContext <Object> resultContext = new DefaultResultContext<Object>();
skipRows(rsw.getResultSet(), rowBounds);
Object rowValue = null;
while (shouldProcessMoreRows( resultContext, rowBounds )
&& rsw.getResultSet().next())
{
final ResultMap discriminatedResultMap =
resolveDiscriminatedResultMap(rsw.getResultSet(),resultMap , null);
// 根据映射字段的值生成缓存key
final CacheKey rowKey =
createRowKey(discriminatedResultMap, rsw, null);
// 在缓存中查询key
Object partialObject = nestedResultObjects.get( rowKey);
// issue
#577 && #542
if (mappedStatement.isResultOrdered())
{
if (partialObject == null && rowValue != null)
{
nestedResultObjects.clear();
storeObject( resultHandler, resultContext, rowValue, parentMapping, rsw.getResultSet());
}
rowValue =
getRowValue( rsw, discriminatedResultMap, rowKey, null, partialObject);
} else {
// 在getRowValue方法中,如果存在缓存就直接取值了
rowValue =
getRowValue( rsw, discriminatedResultMap, rowKey, null, partialObject);
if (partialObject == null)
{
storeObject( resultHandler, resultContext, rowValue, parentMapping, rsw.getResultSet());
}
}
}
if (rowValue != null && mappedStatement.isResultOrdered()
&& shouldProcessMoreRows(resultContext, rowBounds ))
{
storeObject(resultHandler, resultContext, rowValue, parentMapping, rsw.getResultSet());
}
}
getRowValue方法:
private Object
getRowValue(ResultSetWrapper rsw,
ResultMap resultMap,
CacheKey combinedKey,
String columnPrefix,
Object partialObject) throws SQLException
{
final String resultMapId = resultMap.getId();
Object resultObject = partialObject;
if (resultObject != null)
{
final MetaObject metaObject = configuration.newMetaObject( resultObject);
putAncestor(resultObject, resultMapId, columnPrefix);
applyNestedResultMappings (rsw, resultMap , metaObject , columnPrefix , combinedKey, false);
ancestorObjects.remove( resultMapId);
} else {
final ResultLoaderMap lazyLoader = new ResultLoaderMap();
resultObject =
createResultObject( rsw, resultMap, lazyLoader, columnPrefix);
if (resultObject != null &&
!typeHandlerRegistry.hasTypeHandler(resultMap .getType()))
{
final MetaObject metaObject = configuration.newMetaObject( resultObject);
boolean foundValues =
!resultMap.getConstructorResultMappings().isEmpty();
if (shouldApplyAutomaticMappings( resultMap, true))
{
foundValues =
applyAutomaticMappings( rsw, resultMap, metaObject, columnPrefix)
||foundValues;
}
foundValues =
applyPropertyMappings( rsw, resultMap, metaObject, lazyLoader, columnPrefix)
|| foundValues;
putAncestor( resultObject, resultMapId, columnPrefix);
foundValues = applyNestedResultMappings (rsw, resultMap , metaObject , columnPrefix,combinedKey, true)
|| foundValues;
ancestorObjects.remove( resultMapId);
foundValues = lazyLoader.size()
> 0 || foundValues;
resultObject = foundValues ? resultObject : null;
}
if (combinedKey !=
CacheKey. NULL_CACHE_KEY)
{
nestedResultObjects.put( combinedKey, resultObject);
}
}
return resultObject;
}
相关文章推荐
- SourceProvider.getJniDirectories
- Trac 中文语言安装
- 软件 bug 的生命周期
- Firefox2中输入框丢失光标bug的解决方法
- for命令的一些bug分析
- 修正IE下使用CSS属性overflow的bug
- 解决IE6 3像素Bug的css写法
- 跟我学习JScript的Bug与内存管理
- JS注释所产生的bug 即使注释也会执行
- IE本地存储userdata的一个bug说明
- IE在DOM操作有表单控件时的bug
- ie 处理 gif动画 的onload 事件的一个 bug
- 深入浅析mybatis oracle BLOB类型字段保存与读取
- MyBatis MapperProvider MessageFormat拼接批量SQL语句执行报错的原因分析及解决办法
- IIS6 安全性存在超级BUG,快来看
- Android生存指南之:解Bug策略与思路问题的详解
- oracle+mybatis 使用动态Sql当插入字段不确定的情况下实现批量insert
- MyBatis学习笔记(二)之关联关系
- 浅析Mybatis 在CS程序中的应用
- Java Mybatis框架入门基础教程