0

这是我的代码:

HibernateUtil.pushFlushMode(FlushMode.MANUAL);
getCurrSess().beginTransaction();
try {
    for(i=0; i<list.size(); i++) {
        Obj dummy = list.get(i);
        // Here Multiple things can happen like selects, save, update and deletes of different objects which are related to dummy object....
        if (i > 0 && (i % 10 == 0)) {
            getCurrSess().getTran().commit();
            getCurrSess().beginTransaction();
            if (i % BATCH_SIZE == 0) {
                getCurrSess().flush();
                Thread.sleep(20);
            }
        }
    } 
} catch(Exception e) {
    getCurrSess().getTran().rollback();
} finally {
    HibernateUtil.popFlushMode();
}

每 10 个提交的事务 (i=100) 发生一次刷新。这是占用大量处理的后台作业的一部分。对象的数量在 20,000 左右变化,在整个过程完成之前我无法清除会话,因为我最终出现了延迟初始化异常。我的代码工作正常,但在这里我对手动模式下刷新和提交的顺序感到困扰。这可以以更好的方式完成吗?

4

2 回答 2

0

我在一个应用程序中工作,在这种操作过程中我们经常遇到 OptimisticLockExceptions,为了修复它,我们只是重新运行了批处理。不利的一面是,例如,如果您的数据库在批处理中途脱机,您仍然可能会得到一个损坏的数据库。

HibernateUtil.pushFlushMode(FlushMode.MANUAL);
try {
  int batchIndex = 0;
  int numAttempts = 0;
  while (batchIndex < list.size()) {
    listEnd = batchIndex+BATCH_SIZE;
    if(listEnd > list.size()) {
      listEnd = list.size();
    }
    ArrayList<> sublist = new ArrayList<>(list.subList(batchIndex, batchIndex+BATCH_SIZE));
    getCurrSess().beginTransaction();
    try {
      for(Object obj : list) {
        //Here multiple things can happen like selects, save, update, and deletes
      }
      getCurrSess().flush();
      getCurrSess().commit();
      batchIndex += BATCH_SIZE;
    } catch (Exception e) {
      getCurrSess().getTran().rollback();
      numAttempts++;
      if(numAttempts == MAX_ATTEMPTS) {
        throw new RuntimeException("Exceeded maximum number of attempts for batch operation, database is corrupted.");
      }
    }
  }
} finally {
  HibernateUtil.popFlushMode();
}

如果您绝对不能容忍损坏的数据库,那么您必须使用单个事务:

HibernateUtil.pushFlushMode(FlushMode.MANUAL);
try {
    getCurrSess().beginTransaction();
    try {
      for(int i = 0; i < list.size(); i++) {
        Object obj = list.get(i);
        //Here multiple things can happen like selects, save, update, and deletes
        if(i % BATCH_SIZE == 0) {
          getCurrSess().flush();
        }
      }
      getCurrSess().commit();
    } catch (Exception e) {
      throw new RuntimeException("Error occurred during batch.  Batch aborted.");
    }
  }
} finally {
  HibernateUtil.popFlushMode();
}

但显然,如果您有 20,000 个对象,这不会给您带来出色的性能(事实上,即使是第一种方法也不会很好)。如果您确实有 20,000 个对象,那么您能够提高性能的唯一方法是在每批中刷新和清除。这意味着您必须密切管理您的操作方式以避免惰性初始化程序异常。

于 2013-08-21T21:10:47.050 回答
0

10您在模数中使用常量的原因是什么?

你应该总是想做某事是有原因的:-)我的意思是什么?

如果你想提供更好的吞吐量或者你有少量的 RAM,我会在迭代中的每个周期提供缓存刷新和清除,因为小事务带来了这个特性。

如果您没有此要求,则取决于列表的大小是在最后提交还是在迭代期间提交,您尝试如何设计自己。请注意恒定10,因为有时它可能足够,有时很少,有时太多。我更愿意根据其他重要标志来决定何时刷新,例如会话中的对象计数或占用的内存等。请注意,您不仅应该关心休眠缓存的大小,还应该关心数据库事务日志。

如果您关心性能,请查看无状态会话,几年前我已经进行了一些性能测试(.NET)

于 2013-08-22T07:06:10.953 回答