由于为了能在批量插入之后获取到自增id,所以之前用的mybatis需要升级,批量返回的在3.3.1之后才开始支持。
但是升级之后,会有一些问题,对于覆盖重写的类如Configuration等出现的错误,是缺少参数,new一个参数放进去就可以了。但是后来发现之前用的foreach报错了,
报错内容为:There is no getter for property named '__frch_item_0' in 'class xxxx。
之前在网上找了找发现并不是应为mybatis的原因,mybatis3.4对foreach循环的支持没有发生变化。
后来没办法,调试跟踪代码发现是jeeSite上重写的类中对于新版的mybatis的foreach参数处理出现的问题,具体如下:
SQLHelper.java
@SuppressWarnings("unchecked")
public static void setParameters(PreparedStatement ps, MappedStatement mappedStatement, BoundSql boundSql, Object parameterObject) throws SQLException {
ErrorContext.instance().activity("setting parameters").object(mappedStatement.getParameterMap().getId());
List<ParameterMapping> parameterMappings = boundSql.getParameterMappings();
if (parameterMappings != null) {
Configuration configuration = mappedStatement.getConfiguration();
TypeHandlerRegistry typeHandlerRegistry = configuration.getTypeHandlerRegistry();
MetaObject metaObject = parameterObject == null ? null :
configuration.newMetaObject(parameterObject);
for (int i = 0; i < parameterMappings.size(); i++) {
ParameterMapping parameterMapping = parameterMappings.get(i);
if (parameterMapping.getMode() != ParameterMode.OUT) {
Object value;
String propertyName = parameterMapping.getProperty();
PropertyTokenizer prop = new PropertyTokenizer(propertyName);
if (parameterObject == null) {
value = null;
} else if (typeHandlerRegistry.hasTypeHandler(parameterObject.getClass())) {
value = parameterObject;
} else if (boundSql.hasAdditionalParameter(propertyName)) {// list类型foreach应该走到这,但是却到了else里面,是因为boundSql的additionalParameter是空的。
value = boundSql.getAdditionalParameter(propertyName);
} else if (propertyName.startsWith(ForEachSqlNode.ITEM_PREFIX) && boundSql.hasAdditionalParameter(prop.getName())) {
value = boundSql.getAdditionalParameter(prop.getName());
if (value != null) {
value = configuration.newMetaObject(value).getValue(propertyName.substring(prop.getName().length()));
}
} else {
value = metaObject == null ? null : metaObject.getValue(propertyName);
}
@SuppressWarnings("rawtypes")
TypeHandler typeHandler = parameterMapping.getTypeHandler();
if (typeHandler == null) {
throw new ExecutorException("There was no TypeHandler found for parameter " + propertyName + " of statement " + mappedStatement.getId());
}
typeHandler.setParameter(ps, i + 1, value, parameterMapping.getJdbcType());
}
}
}
}
list类型foreach应该走到这,但是却到了else里面,是因为boundSql的additionalParameter是空的。所以到上一级调用类中见additionalParameter加上就可以了。如下:
SQLHelper-getCount中:
public static int getCount(final String sql, final Connection connection,
final MappedStatement mappedStatement, final Object parameterObject,
final BoundSql boundSql, Log log) throws SQLException {
String dbName = Global.getConfig("jdbc.type");
final String countSql;
if("oracle".equals(dbName)){
countSql = "select count(1) from (" + sql + ") tmp_count";
}else{
countSql = "select count(1) from (" + removeOrders(sql) + ") tmp_count";
// countSql = "select count(1) " + removeSelect(removeOrders(sql));
}
Connection conn = connection;
PreparedStatement ps = null;
ResultSet rs = null;
try {
if (log.isDebugEnabled()) {
log.debug("COUNT SQL: " + StringUtils.replaceEach(countSql, new String[]{"\n","\t"}, new String[]{" "," "}));
}
if (conn == null){
conn = mappedStatement.getConfiguration().getEnvironment().getDataSource().getConnection();
}
ps = conn.prepareStatement(countSql);
BoundSql countBS = new BoundSql(mappedStatement.getConfiguration(), countSql,
boundSql.getParameterMappings(), parameterObject);
//解决MyBatis 分页foreach list item问题! 升级3.4.0后的问题 此部分为新增内容
if (Reflections.getFieldValue(boundSql, "additionalParameters") != null) {
@SuppressWarnings("unchecked")
Map<String, Object> mo = (Map<String, Object>) Reflections.getFieldValue(boundSql, "additionalParameters");
Reflections.setFieldValue(countBS, "additionalParameters", mo);
}
//升级3.4.0后的问题 此部分为新增内容 end
//解决MyBatis 分页foreach 参数失效 start
if (Reflections.getFieldValue(boundSql, "metaParameters") != null) {
MetaObject mo = (MetaObject) Reflections.getFieldValue(boundSql, "metaParameters");
Reflections.setFieldValue(countBS, "metaParameters", mo);
}
//解决MyBatis 分页foreach 参数失效 end
SQLHelper.setParameters(ps, mappedStatement, countBS, parameterObject);
rs = ps.executeQuery();
int count = 0;
if (rs.next()) {
count = rs.getInt(1);
}
return count;
} finally {
if (rs != null) {
rs.close();
}
if (ps != null) {
ps.close();
}
if (conn != null) {
conn.close();
}
}
}
除此之外,还要在PaginationInterceptor.java中增加一部分处理如下:
@Override
public Object intercept(Invocation invocation) throws Throwable {
final MappedStatement mappedStatement = (MappedStatement) invocation.getArgs()[0];
// //拦截需要分页的SQL
if (mappedStatement.getId().matches(_SQL_PATTERN)) {
// if (StringUtils.indexOfIgnoreCase(mappedStatement.getId(), _SQL_PATTERN) != -1) {
Object parameter = invocation.getArgs()[1];
BoundSql boundSql = mappedStatement.getBoundSql(parameter);
Object parameterObject = boundSql.getParameterObject();
//获取分页参数对象
Page<Object> page = null;
if (parameterObject != null) {
page = convertParameter(parameterObject, page);
}
//如果设置了分页对象,则进行分页
if (page != null && page.getPageSize() != -1) {
if (StringUtils.isBlank(boundSql.getSql())){
return null;
}
String originalSql = boundSql.getSql().trim();
//得到总记录数
page.setCount(SQLHelper.getCount(originalSql, null, mappedStatement, parameterObject, boundSql, log));
//分页查询 本地化对象 修改数据库注意修改实现
String pageSql = SQLHelper.generatePageSql(originalSql, page, DIALECT);
// if (log.isDebugEnabled()) {
// log.debug("PAGE SQL:" + StringUtils.replace(pageSql, "\n", ""));
// }
invocation.getArgs()[2] = new RowBounds(RowBounds.NO_ROW_OFFSET, RowBounds.NO_ROW_LIMIT);
BoundSql newBoundSql = new BoundSql(mappedStatement.getConfiguration(), pageSql, boundSql.getParameterMappings(), boundSql.getParameterObject());
//解决MyBatis 分页foreach list item问题! 升级3.4.0后的问题 此部分新增
if (Reflections.getFieldValue(boundSql, "additionalParameters") != null) {
@SuppressWarnings("unchecked")
Map<String, Object> mo = (Map<String, Object>) Reflections.getFieldValue(boundSql, "additionalParameters");
Reflections.setFieldValue(newBoundSql, "additionalParameters", mo);
}
//解决MyBatis 分页foreach list item问题! 升级3.4.0后的问题 此部分新增,end
//解决MyBatis 分页foreach 参数失效 start
if (Reflections.getFieldValue(boundSql, "metaParameters") != null) {
MetaObject mo = (MetaObject) Reflections.getFieldValue(boundSql, "metaParameters");
Reflections.setFieldValue(newBoundSql, "metaParameters", mo);
}
//解决MyBatis 分页foreach 参数失效 end
MappedStatement newMs = copyFromMappedStatement(mappedStatement, new BoundSqlSqlSource(newBoundSql));
invocation.getArgs()[0] = newMs;
}
// }
return invocation.proceed();
}
注意:升级后的项目,activiti工作流将不能正常使用,原因是Mybatis版本过高与Activiti不再兼容,需要升级Activiti。