2

我正在使用带有 mysql 和 hibernate 4 和 c3p0 的球衣。我创建了一个初始化 servlet,它配置休眠并将当前会话上下文类设置为线程。我创建了 hibernateUtils 类,其中包含用于获取和提交会话的静态方法,并且我正在使用过滤器在入站请求上启动会话并在响应时提交它。

问题是,在某些随机时间间隔,我得到 org.hibernate.TransactionException: nested transactions not supported 异常,但我没有尝试在过滤器上创建新会话。

如果我错了,请纠正我,但是在将当前会话类设置为线程时,我不需要在 hibernateutil 中创建 threadlocal,hibernate 会这样做。所以我的问题是,这是一种安全的处理方法吗?什么可能导致随机间隔发生错误?

====================== 编辑 ===========================

很抱歉没有早点发布代码。所以过滤器实现了ContainerRequestFilter,ContainerResponseFilter

在我正在做的请求过滤器中

Session session = sessionfactory.getCurrentSession();
session.getTransaction().begin();
session.setDefaultReadOnly(readOnly);

并在回应中

Transaction transaction = sessionfactory.getCurrentSession().getTransaction();
try {
    if (transaction != null && !transaction.wasCommitted()
       && !transaction.wasRolledBack() && transaction.isActive()) {
        transaction.commit();
    }
} catch (HibernateException e) {
    Transaction transaction = sessionfactory.getCurrentSession().getTransaction();
    try {
        if (transaction != null && transaction.isActive()) {
            transaction.rollback();
        }
    } catch (HibernateException e) {

    } finally {
         Session session = sessionfactory.getCurrentSession();
         try {
              if (session != null && session.isOpen()) {
                  session.close();
              }
         } catch (HibernateException e) {
            log.error("Closing session after rollback error: ", e);
            throw e;
     }

}

4

1 回答 1

1

似乎您在过滤器中使用了程序化事务划分(据我所知)。因此,请仔细检查您是否正确终止了每个事务,不要介意在请求期间附加什么(即,如果您遇到异常则回滚并提交):

try {
    session.getTransaction().begin();
    // call the filter chain
    session.getTransaction().commit()
}
catch (RuntimeException e) {
    session.getTransaction().rollback();
}

没有代码很难确定,但我猜对于某些请求,您没有正确终止事务(即通过提交或回滚)。所以事务仍然与线程关联,线程回到线程池(处于非常奇怪的状态,因为仍然有一个事务与之关联),然后另一个请求重用同一个线程,在过滤器中创建一个新事务...你得到了例外。

编辑

在仔细查看您的代码后,它(可能)证实了我的假设。

查看流程 when transaction.wasRolledBack()==true: 它不会被提交也不会回滚。

如果你是Transaction.wasRolledBack()的 javadoc :

此事务是回滚还是设置为仅回滚

如果事务被标记为“仅回滚”:它会返回 true,但并不意味着事务结束。这意味着事务唯一可能的结束状态是“回滚”。

但是,另一方面,同一个 javadoc 也这样说:

返回: boolean 如果事务通过此本地事务回滚,则为 True;否则为假。

我发现这很模棱两可。

所以我建议你这样做:

if (transaction != null && !transaction.wasCommitted()
   && !transaction.wasRolledBack() && transaction.isActive()) {
    transaction.commit();
}else if(transaction.wasRolledBack()){
    transaction.rollback();
}
于 2013-09-12T20:57:58.910 回答