【问题标题】:Creating multiple transactions in a single hibernate session在单个休眠会话中创建多个事务
【发布时间】:2013-05-19 06:06:15
【问题描述】:

我创建了一个 Quartz Job,它在我的 JBoss 服务器的后台运行,负责定期更新一些统计数据(加上一些数据库标志)

要加载和持久化我正在使用 Hibernate 4。除了一个小问题,一切正常。

整个线程,即作业被包装在一个单一的事务中,随着时间的推移(随着数据量的增加)变得巨大并且令人担忧。我试图将这个单一的大事务分解成多个小的事务,这样每个事务只处理一个子组数据。

问题:我非常笨拙地尝试将代码包装到循环中并在循环的开始/结束处开始/结束事务。正如我所料,它没有用。我一直在寻找各种论坛以找出解决方案,但没有遇到任何表明在单个会话中管理多个事务(一次只有一个事务将处于活动状态)的任何内容。

我对 hibernate 比较陌生,如果有任何帮助可以为我指明实现这一目标的方向,我将不胜感激。

更新:添加代码演示了我想要实现的目标以及我所说的闯入多个事务时的意思。以及执行时的堆栈跟踪。

    log.info("Starting Calculation Job.");

    List<GroupModel> groups = Collections.emptyList();
    DAOFactory hibDaoFactory = null;
    try {
        hibDaoFactory = DAOFactory.hibernate();
        hibDaoFactory.beginTransaction();
        OrganizationDao groupDao = hibDaoFactory.getGroupDao();
        groups = groupDao.findAll();
        hibDaoFactory.commitTransaction();
    } catch (Exception ex) {
        hibDaoFactory.rollbackTransaction();
        log.error("Error in transaction", ex);
    }

    try {
        hibDaoFactory = DAOFactory.hibernate();
        StatsDao statsDao = hibDaoFactory.getStatsDao();
        StatsScaledValuesDao statsScaledDao = hibDaoFactory.getStatsScaledValuesDao();

        for (GroupModel grp : groups) {
            try {
                hibDaoFactory.beginTransaction();
                log.info("Performing computation for Group " + grp.getName() + " ["
                        + grp.getId() + "]");

                List<Stats> statsDetail = statsDao.loadStatsGroup(grp.getId());

                // Coputing Steps here

                for (Entry origEntry : statsEntries) {
                    entry.setCalculatedItem1(origEntry.getCalculatedItem1());
                    entry.setCalculatedItem2(origEntry.getCalculatedItem2());
                    entry.setCalculatedItem3(origEntry.getCalculatedItem3());

                    StatsDetailsScaledValues scValues = entry.getScaledValues();
                    if (scValues == null) {
                        scValues = new StatsDetailsScaledValues();
                        scValues.setId(origEntry.getScrEntryId());
                        scValues.setValues(origEntry.getScaledValues());
                    } else {
                        scValues.setValues(origEntry.getScaledValues());
                    }
                    statsScaledDao.makePersistent(scValues);
                }

                hibDaoFactory.commitTransaction();
            } catch (Exception ex) {
                hibDaoFactory.rollbackTransaction();
                log.error("Error in transaction", ex);
            } finally {

            }
        }
    } catch (Exception ex) {
        log.error("Error", ex);
    } finally {

    }

    log.info("Job Complete.");

以下是我在执行此作业时遇到的异常堆栈跟踪

org.hibernate.SessionException: Session is closed!
    at org.hibernate.internal.AbstractSessionImpl.errorIfClosed(AbstractSessionImpl.java:127)
    at org.hibernate.internal.SessionImpl.createCriteria(SessionImpl.java:1555)
    at sun.reflect.GeneratedMethodAccessor469.invoke(Unknown Source)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source)
    at java.lang.reflect.Method.invoke(Unknown Source)
    at org.hibernate.context.internal.ThreadLocalSessionContext$TransactionProtectionWrapper.invoke(ThreadLocalSessionContext.java:352)
    at $Proxy308.createCriteria(Unknown Source)
    at com.blueoptima.cs.dao.impl.hibernate.GenericHibernateDao.findByCriteria(GenericHibernateDao.java:132)
    at com.blueoptima.cs.dao.impl.hibernate.ScrStatsManagementHibernateDao.loadStatsEntriesForOrg(ScrStatsManagementHibernateDao.java:22)
    ... 3 more

根据我目前所读到的关于 Hibernate、会话和事务的理解。似乎在创建会话时,它会附加到线程并在线程生命周期内或调用提交或回滚时存在。因此,当提交第一个事务时,会话将被关闭,并且在线程的剩余生命周期内不可用。

我的问题仍然存在:我们如何在一个会话中进行多个事务?

【问题讨论】:

  • 那么如果第二(三、四)次“交易”失败了怎么办?您如何处理以前的数据?听起来像是一种可能会破坏您所有数据的黑客行为。您不应该根据性能定义事务,而是根据业务规则的需要。开始寻找“变慢”的原因(无论如何对我来说听起来很奇怪)。
  • 还有:您使用的是哪个 DBMS?后格雷斯?甲骨文?
  • @a_horse_with_no_name 这不是 hack。数据本身按一个键分组,每个组可以包含从几百条记录到一百万条记录的数据。以防特定交易失败。管理员已意识到这一点,因此必须成功处理和保存所有组。我正在使用 Postgres。总而言之,成功完成的事务必须写入数据库,失败的事务必须回滚。这不会相互影响。我希望这能解释我的要求。谢谢。
  • 您的业务规则要么要求所有内容都在一个事务中,然后将其分解是一种“黑客行为”。或者你的业务规则不需要这个,那么现有的代码是错误的。要将事务(您的业务规则要求)拆分为较小的事务,不正确的 - 特别是如果它只是为了性能。
  • “没用”。呃....细节? 错误消息?确切的 PostgreSQL 版本? 代码?

标签: java hibernate postgresql transactions


【解决方案1】:

更多细节和一些例子会很好,但我想我应该能够帮助你在这里写的东西。

拥有一个静态 SessionFactory(这对内存来说很大) 您还想要这样的交易。

SomeClass object = new SomeClass();

Session session = sessionFactory().openSession() // create the session object
session.beginTransaction(); //begins the transaction
session.save(object); // saves the object But REMEMBER it isn't saved till session.commit()
session.getTransaction().commit(); // actually persisting the object
session.close(); //closes the transaction

这就是我使用我的交易的方式,我不确定我是否一次完成了与您一样多的交易。但是与内存中的 SessionFactory 相比,会话对象是轻量级的。

例如,如果您想一次保存更多对象,可以在一个事务中完成。

SomeClass object1 = new SomeClass();
SomeClass object2 = new SomeClass();
SomeClass object2 = new SomeClass();

session.beginTransaction();
session.save(object1);
session.save(object2);
session.save(object3);
session.getTransaction().commit(); // when commit is called it will save all 3 objects
session.close();

希望这对您有所帮助或为您指明正确的方向。 我认为您也可以将程序配置为压缩交易。 :)

编辑 这是一个很棒的 youtube 教程。这家伙真的为我打破了它。

Hibernate Tutorials

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2012-11-11
    • 1970-01-01
    • 2018-09-14
    • 1970-01-01
    • 1970-01-01
    • 2017-08-04
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多