【问题标题】:Can you have multiple transactions within one Hibernate Session?你可以在一个 Hibernate Session 中有多个事务吗?
【发布时间】:2014-11-11 15:52:15
【问题描述】:

你可以在一个 Hibernate Session 中有多个事务吗?

我不清楚这是否是可取的。在我的代码中,我有一个长时间运行的线程并从阻塞队列中获取项目,这取决于队列中的内容,它可能需要创建和保存一个休眠对象,或者它可能不需要做任何事情。

每个项目都是不同的,所以如果项目 1 被保存并且项目 2 未能保存任何我不想阻止项目 1 被添加到数据库的原因。

所以最简单的方法是为每个需要创建的项目创建一个新会话、打开事务、保存新对象、提交事务、关闭会话

但是,这意味着为每个项目创建一个新会话,这似乎违背了 Hibernates 自己的建议,即不执行 Session Per Request Pattern。所以我的替代方法是在线程中创建一个会话,然后在需要创建新对象时根据需要打开并提交一个新事务。但我没有看到这种方法的例子,我不确定它是否真的有效。

【问题讨论】:

标签: java database hibernate session transactions


【解决方案1】:

来自休眠文档

“会话是一个廉价的、非线程安全的对象,应该使用一次然后丢弃:单个请求、会话或单个工作单元。会话不会获得 JDBC 连接或数据源,除非需要,否则不会消耗任何资源。”

因此,如果您一次又一次地创建会话,它不会给系统带来太多负担。如果您继续会话太久,它可能会产生问题,因为会话不是线程安全的。在我看来,您最简单的解决方案是最好的“所以最简单的方法是针对需要创建的每个项目来创建一个新的会话,打开事务,保存新对象,提交事务,关闭会话"

顺便说一句,如果您正在创建任何不需要太多事务的单一记录。创建单个记录本质上是我们使用事务的“全部或全部”的事情

【讨论】:

  • 线程安全不是问题,因为在这种情况下,所有代码都在一个线程上运行。
  • 对多个事务使用单个会话的另一个缺点是对象不会自动驱逐,并且会话将继续增长其大小,这可能会导致内存不足错误。
【解决方案2】:

简短的回答是肯定的,您可以使用相同的会话进行交易。看看org.hibernate.Transaction.,它有管理事务的方法。

【讨论】:

    【解决方案3】:

    显然,你可以。休眠会话或多或少是数据库连接和数据库对象的缓存。您可以在单个数据库连接中拥有多个连续事务。而且,当你使用连接池时,连接并没有关闭,而是被回收。

    是否应该重用会话中的对象是一个问题。如果有很好的机会,但您可以重用前一个事务已放入会话的对象,您应该为多个事务保留一个会话。但是如果一个对象一旦被提交,就永远不会被重新使用,当然最好关闭会话并重新打开一个新的,或者干脆清除它。

    怎么做:

    如果你有一个 Session 对象,你可以创建事务:

    Transaction transaction;
    transaction = session.beginTransaction();
    ... (operations in the context of transaction)
    transaction.commit();
    ... (other commands outside of any transaction)
    transaction = session.beginTransaction();
    ... (and so on and so forth ...)
    

    【讨论】:

      【解决方案4】:

      如果您运行本地事务,则每个请求的会话模式每个会话使用一个 JDBC 连接。对于 JTA,连接会在每条语句后积极释放,只为下一条语句重新获取。

      Hibernate 事务 API 将 begin/commit/rollback 委托给本地事务的 JDBC Connection 和 JTA 的关联 UserTransaction。因此,您可以在同一个 Hibernate Session 上运行多个事务,但有一个问题。一旦抛出异常,您就不能再重用该 Session。

      我的建议是分而治之。只需拆分所有项目,为每个项目构建一个 Command 对象并将它们发送到ExecutorService#invokeAll。使用返回的 List 进行迭代并调用 Future#get() 以确保原始线程在所有批处理作业完成后等待。

      ExecutorService 将确保您同时运行所有命令,并且每个命令都应使用使用自己的@Transaction 的服务。因为事务是线程绑定的,所以您将拥有所有 batch jobs run in isolation

      【讨论】:

      • '一旦抛出异常,您就不能再重用该会话。' - 我认为这是他们以前可能给我造成问题并在一个会话中为我破坏多个 txns 的关键点,谢谢
      • @VladMihalcea 您能否解释一下为什么如果出现异常我们不能重用会话?是因为hibernate在抛出异常时回滚事务并关闭会话吗?还是其他原因?
      • @VladMihalcea 非常感谢您的回答。我能理解你的回答,但我认为我在休眠缓存和同步方面的知识非常有限。
      • @VladMihalcea 阅读示例章节后,我刚从 ebay 订购了一本您的书。
      • 可能是一些中介。 Leanpub 是电子书和亚马逊平装书的原始出版商。我想这两个提供最优惠的价格。
      【解决方案5】:
      package hibernate;
      import org.hibernate.Session;
      import org.hibernate.SessionFactory;
      import org.hibernate.boot.registry.StandardServiceRegistryBuilder;
      class Tester {
      public static void main(String[] args) {
          SessionFactory sf = new org.hibernate.cfg.Configuration().configure().buildSessionFactory(new StandardServiceRegistryBuilder().configure().build());
          Session session = sf.openSession();
          session.beginTransaction();
              Student student = new Student();
          student.setName("Mr X");
          student.setRollNo(13090);
              session.save(student);
          session.getTransaction().commit();
          session.getTransaction().begin();
          session.load(Student.class,23);
          student.setName("New Name");
          student.setRollNo(123);
          session.update(student);
          session.getTransaction().commit();
          session.close();
        }
      }
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2010-11-26
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多