我们正在将我们的MySQL版本从5.7.16升级到5.7.18。我们的现有流程似乎与较新版本的MySQL不兼容。
这是一个分页过程,通过一次500个来更新多达100,000行。它在5.7.16以及之前版本的MySQL上运行良好多年。由于我们升级了该过程,因此只会执行500行几次,然后继续执行后续步骤。例如,它将更新500行3次,然后在第四次更新仅1行。有时它会更新500行5次,然后第六次它将再次更新1行。似乎可疑的是,进程迭代了几次,然后在最后一次总是只有1行。
我们的旧实现是否与LIMIT或ORDER BY的新版MySQL不兼容?这是我们认为可能导致失败的两件事。我们很容易注意到这个领域的失败,但是我们需要知道为什么一个实现工作而不是另一个实现,以便我们可以在代码库中找到故障不太明显的任何其他区域。
不适用于MySQL 5.7.18的旧实现:
public void changeItemsType(TypeEnum inProgress, TypeEnum complete) {
int howMany = 500;
int selectSize = howMany;
Long lastId = 0L;
while (selectSize == howMany) {
Query q = null;
q = buildChangeQuery(inProgress, howMany, lastId);
List<BigInteger> rows = GenericsUtil.cast(q.getResultList());
selectSize = rows.size();
if (rows != null && !rows.isEmpty()) {
lastId = buildIdUpdateList(complete, lastId, rows, inProgress);
}
}
}
private Query buildChangeQuery(TypeEnum inProgress, int howMany, Long lastId) {
StringBuffer sb = new StringBuffer();
sb.append("select id from Item \n");
sb.append("where processType = :inprogress \n");
sb.append("and id > :lastId \n");
sb.append("order by id \n");
Query q = this.em.createNativeQuery(sb.toString());
q.setParameter("inprogress", inProgress.name());
q.setParameter("lastId", lastId);
q.setMaxResults(howMany);
return q;
}
private Long buildIdUpdateList(TypeEnum complete, Long lastId, List<BigInteger> rows, TypeEnum inProgress) {
List<Long> ids = new ArrayList<Long>();
Long itemId = 0L;
for (BigInteger row : rows) {
itemId = row.longValue();
ids.add(itemId);
}
lastId = itemId;
updateItems(complete, ids, inProgress);
return lastId;
}
private void updateItems(TypeEnum complete, List<Long> ids, TypeEnum inProgress) {
Collections.sort(ids);
StringBuffer sb = new StringBuffer();
sb.append("update Item \n");
sb.append("set type = :complete, \n");
sb.append("updateDate = :now, \n");
sb.append("version = version + 1, \n");
sb.append("updateAction = :inProgress \n");
sb.append("where id in (:ids) \n");
Query q = this.em.createNativeQuery(sb.toString());
q.setParameter("complete", complete.name());
q.setParameter("ids", ids);
q.setParameter("now", new Date());
q.setParameter("inProgress", inProgress.name().replaceAll("IN_PROGRESS_", ""));
q.executeUpdate();
}
同一进程的新实现,它与MySQL 5.7.18一起使用:
public void changeItemsType(TypeEnum inProgress, TypeEnum complete, int howMany) {
int updateCount = -1;
while (updateCount != 0) {
updateCount = 0;
updateCount = updateItems(inProgress, complete, howMany);
}
}
private int updateItems(TypeEnum inProgress, TypeEnum complete, int howMany) {
StringBuffer sb = new StringBuffer();
sb.append("update Item \n");
sb.append("set processType = :complete, \n");
sb.append("updateDate = :now, \n");
sb.append("version = version + 1, \n");
sb.append("updateAction = :inProgress \n");
sb.append("where type = :inProgressTemp \n");
Query q = this.em.createNativeQuery(sb.toString());
q.setParameter("inProgressTemp", inProgress.name());
q.setParameter("complete", complete.name());
q.setParameter("now", new Date());
q.setParameter("inProgress", inProgress.name().replaceAll("IN_PROGRESS_", ""));
q.setMaxResults(howMany);
int updateSize = 0;
updateSize = q.executeUpdate();
return updateSize;
}