当前位置: 首页 > 面试题库 >

在大型事务中安全清除Hibernate会话

益源
2023-03-14
问题内容

我将Spring + Hibernate用于需要创建和更新数十万个项目的操作。像这样:

{
   ...
   Foo foo = fooDAO.get(...);
   for (int i=0; i<500000; i++) {
      Bar bar = barDAO.load(i);
      if (bar.needsModification() && foo.foo()) {
         bar.setWhatever("new whatever");
         barDAO.update(bar);
         // commit here
         Baz baz = new Baz();
         bazDAO.create(baz);
         // if (i % 100 == 0), clear
      }
   }
}

为了防止自己丢失中间的更改,我会在之后立即提交更改barDAO.update(bar)

HibernateTransactionManager transactionManager = ...; // injected by Spring
DefaultTransactionDefinition def = new DefaultTransactionDefinition();
def.setPropagationBehavior(TransactionDefinition.PROPAGATION_REQUIRED);
TransactionStatus transactionStatus = transactionManager.getTransaction(def);
transactionManager.commit(transactionStatus);

在这一点上,我不得不说整个过程都在包装成的事务中运行org.springframework.orm.hibernate3.support.ExtendedOpenSessionInViewFilter(是的,这是一个webapp)。

这一切都很好,但有一个例外:经过数千次更新/提交后,整个过程确实变慢了,这很可能是由于Spring /
Hibernate保存的对象数量不断增加而导致内存膨胀。

在仅hibernate的环境中,可以通过调用轻松解决org.hibernate.Session#clear()

现在,问题是:

  • 什么时候是个好时机clear()?它有很大的性能成本吗?
  • 为什么没有自动喜欢barbaz释放/ GCd的对象?在提交后将它们保留在会话中有什么意义(在下一个迭代循环中,它们始终无法访问)?我没有做内存转储来证明这一点,但是我的好感觉是它们仍然存在直到完全退出。如果答案是“hibernate缓存”,那么为什么在可用内存变低时不刷新缓存?
  • org.hibernate.Session#clear()直接调用是否安全/建议(考虑到整个Spring上下文,诸如延迟加载之类的事情)?是否有任何可用的Spring包装器/配对部件可实现相同目的?
  • 如果对上述问题的回答是正确的,则foo假设clear()在循环内调用object会发生什么?如果foo.foo()是延迟加载方法怎么办?

谢谢你的回答。


问题答案:

什么时候是clear()的好时机?它有很大的性能成本吗?

刷新更改后,应按固定的时间间隔,最好与JDBC批处理大小相同。该文档在有关批处理的章节中描述了常见的成语:

13.1。批量插入

在使新对象持久化flush()然后定期清除()时,会话将控制一级缓存的大小。

Session session = sessionFactory.openSession();
Transaction tx = session.beginTransaction();

for ( int i=0; i<100000; i++ ) {
    Customer customer = new Customer(.....);
    session.save(customer);
    if ( i % 20 == 0 ) { //20, same as the JDBC batch size
        //flush a batch of inserts and release memory:
        session.flush();
        session.clear();
    }
}

tx.commit();
session.close();

与此相反,这不应该 降低 性能 成本

  • 它可以使要跟踪的污物数量保持在较低水平(因此冲洗应该很快),
  • 它应该允许回收内存。

为什么不自动释放bar或baz之类的对象/ GCd?在提交后将它们保留在会话中有什么意义(在下一个迭代循环中它们始终无法访问)?

clear()如果您不想跟踪实体,就需要显式地进行会话,仅此而已(它可能是这样工作的(一个人可能想提交事务而不“丢失”实体))。

但是据我所知,bar和baz实例应在清除后成为GC的候选对象。分析内存转储以查看发生了什么会很有趣。

直接调用org.hibernate.Session#clear()是否安全/建议

只要您flush()有待执行的更改而不丢失它们(除非这是您想要的),我就不会发现任何问题(您当前的代码每100个循环会丢失一次create,但这也许只是一些伪代码)。

如果对上述问题的回答是正确的,假设在循环内调用了clear(),对象foo将会发生什么?如果foo.foo()是延迟加载方法怎么办?

调用clear()将所有加载的实例从中逐出Session,使它们成为分离的实体。如果后续调用要求实体被“附加”,它将失败。



 类似资料:
  • 我对Hibernate中的会话和事务的概念有点困惑。据我所知,Hibernate使用会话(持久性上下文),它基本上是需要持久,删除或数据库中任何内容的实体的缓存。会话封装事务,因此我启动一个会话,然后创建一个事务。事务关闭后,持久性上下文中的所有内容都将刷新到数据库,如果我关闭会话,也会发生同样的事情。 为什么我需要两者?我可以在不创建交易的情况下做同样的事情吗?

  • 问题内容: 我知道会话不是线程安全的。我的第一个问题:将实体传递给另一个线程,对它做一些工作,然后将其传递回原始线程并进行更新,是否安全? 我的第二个问题:在一个线程中创建一个实体并将其保存在另一个线程中是否安全? 编辑 我忘了提到实体是为快速加载而专门配置的 问题答案: 否。该实体已附加到会话中,并包含链接到该会话的代理(以延迟自身加载)。因此,这样做将使用多个线程中的会话。由于会话不是线程安全

  • 问题内容: 我有一个Angular指令,该指令将元素的高度设置为等于浏览器窗口的内部高度(+/-给定的偏移量)。该指令响应窗口的“调整大小”事件,并相应地调整其高度。当指令的作用域发出’$ destory’事件时,我将删除对“ resize”事件的绑定(我认为将其留在原地会引起一些问题,如果我错了,请纠正我)。 我不知道如何以“安全”的方式执行此事件分离。如果我在整个应用程序中都有该指令的多个实例

  • 问题内容: 我们将MySQL与InnoDB存储引擎和事务一起大量使用,并且遇到了一个问题:我们需要一种很好的方法来在MySQL中模拟Oracle的SEQUENCE。要求是:-并发支持- 事务安全-最大性能(意味着最小化锁和死锁) 我们不在乎是否不会使用某些值,即顺序上的间隔是可以的。有一个简单的方法来存档,即通过创建一个带有计数器的单独的InnoDB表,但这意味着它将参与事务并引入锁和等待。我正在

  • 问题内容: 我需要知道,hibernate的会话是否是线程安全的。但是很明显,新会话将附加到每个线程以执行。但是我的问题是,如果在一个线程中我已经更新了某个实体的某个值,那么这将在同一时间执行期间反映在另一个线程中吗? 我的问题是,当我依次从两个线程启动更新时,值会正确更新,但是当我几乎完全启动更新时,它将失败。 例如 表的当前阶段。 我正在尝试以下: 当我尝试在循环中运行上述代码(例如10)时,

  • 我正在将代码从EJB迁移到Spring-Hibernate。如果发生故障,如何加入事务并回滚?下面是EJB中的代码: 更新1:我们如何连接发生在不同数据库上的两个事务?有2个事务需要原子地执行。如果第二个事务失败,则必须回滚第一个事务。对此如何落实?