0

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

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

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

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

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

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

    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、会话和事务的理解。似乎在创建会话时,它会附加到线程并在线程生命周期内或调用提交或回滚时存在。因此,当提交第一个事务时,会话将被关闭,并且在线程的剩余生命周期中不可用。

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

4

1 回答 1

2

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

拥有一个静态 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 教程。这家伙真的为我打破了它。

休眠教程

于 2013-05-19T06:16:25.550 回答