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

如何避免嵌套事务不支持的错误?

樊奇思
2023-03-14
问题内容

我需要确保许多并发用户能够访问数据库。虽然在每次提交后我都关闭了会话,但是有时我的代码遇到以下错误,但是当我几次执行相同的操作时,它会超过错误并可以正常工作。

我的hibernate状态是4.2.1。

Messages:   
nested transactions not supported
File:   org/hibernate/engine/transaction/spi/AbstractTransactionImpl.java
Line number:    152

我的密码

session = HibernateUtil.getSession();
session.getTransaction().begin();       OR session.beginTransaction();
       ...   to do ....
session.getTransaction().commit();
session.close();                        OR HibernateUtil.closeSession();

HibernateUtil

import org.hibernate.HibernateException;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.cfg.Configuration;
import org.hibernate.service.ServiceRegistry;
import org.hibernate.service.ServiceRegistryBuilder;

public class HibernateUtil {

   private static ServiceRegistry serviceRegistry;
   private static final ThreadLocal<Session> threadLocal = new ThreadLocal();
   private static SessionFactory sessionFactory;
    private static SessionFactory configureSessionFactory() {
        try {

            Configuration configuration = new Configuration();
            configuration.configure();
            serviceRegistry = new ServiceRegistryBuilder()
                                 .applySettings(configuration.getProperties())
                                 .buildServiceRegistry();
            sessionFactory = configuration.buildSessionFactory(serviceRegistry);

            return sessionFactory;
        } catch (HibernateException e) {
            System.out.append("** Exception in SessionFactory **");
            e.printStackTrace();
        }
       return sessionFactory;
  }


  static {
    try {
      sessionFactory = configureSessionFactory();
    } catch (Exception e) {
      System.err.println("%%%% Error Creating SessionFactory %%%%");
      e.printStackTrace();
    }
  }

  private HibernateUtil() {
  }

  public static SessionFactory getSessionFactory() {
    return sessionFactory;
  }

  public static Session getSession() throws HibernateException {
    Session session = threadLocal.get();

    if (session == null || !session.isOpen()) {
      if (sessionFactory == null) {
        rebuildSessionFactory();
      }
      session = (sessionFactory != null) ? sessionFactory.openSession() : null;
      threadLocal.set(session);
    }

    return session;
  }

  public static void rebuildSessionFactory() {
    try {
      sessionFactory = configureSessionFactory();
    } catch (Exception e) {
      System.err.println("%%%% Error Creating SessionFactory %%%%");
      e.printStackTrace();
    }
  }

  public static void closeSession() throws HibernateException {
    Session session = (Session) threadLocal.get();
    threadLocal.set(null);

    if (session != null) {
      session.close();
    }
  }
}

组态

<?xml version='1.0' encoding='utf-8'?>
<!DOCTYPE hibernate-configuration PUBLIC
        "-//Hibernate/Hibernate Configuration DTD 3.0//EN"
        "http://www.hibernate.org/dtd/hibernate-configuration-3.0.dtd">

<hibernate-configuration>

    <session-factory>

        <!-- Database connection settings -->
        <property name="connection.driver_class">
            com.mysql.jdbc.Driver
        </property>
        <property name="connection.url">
            jdbc:mysql://localhost:3306/MyProject
        </property>
        <property name="connection.username">root</property>
        <property name="connection.password"></property>

        <!-- JDBC connection pool (use the built-in) -->
        <property name="connection.pool_size">12</property>

        <!-- SQL dialect -->
        <property name="dialect">
            org.hibernate.dialect.MySQLDialect
        </property>

        <!-- Enable Hibernate's automatic session context management -->
        <property name="current_session_context_class">thread</property>

        <!-- Disable the second-level cache  -->
        <property name="cache.provider_class">
            org.hibernate.cache.NoCacheProvider
        </property>

        <!-- Echo all executed SQL to stdout -->
        <property name="show_sql">true</property>

                <mapping class="com.project.common.Project" />
                <mapping class="com.project.common.School" />
                <mapping class="com.project.common.Address" />
                <mapping class="com.project.common.Female" />
                <mapping class="com.project.common.Male" />
                <mapping class="com.project.common.Credential" />
                <mapping class="com.project.common.Users" />

    </session-factory>

</hibernate-configuration>

问题答案:

在您的“我的代码”代码段中,可能存在一些问题:

  1. 发生异常时,没有finally阻止关闭会话的块
  2. 您正在打电话session.close(),但这与有所不同HibernateUtils.closeSession()。因此,ThreadLocal不会清除。
  3. 没有catch例外。结果是没有rollback
  4. 您是抛出异常还是被(静默)忽略?

如果之后的“待办事项”块中有异常begin(),则事务保持打开状态,并且ThreadLocal不清除。

您的代码可能正常工作,但是在高负载下可能会发生(SQL锁定)超时等情况,在这种情况下,偶尔会抛出异常。

因此,请检查 每个 代码段以进行 正确的 异常处理:

final Session session = HibernateUtil.getSession();
try {
  final Transaction transaction = session.beginTransaction();
  try {
    // The real work is here
    transaction.commit();
  } catch (Exception ex) {
    // Log the exception here
    transaction.rollback();
    throw ex;
  }
} finally {
  HibernatilUtil.closeSession();
}

您可以向HibernateUtil.getSession()和添加一些“簿记”代码HibernateUtil.closeSession():记录每次访问,包括线程的名称。最终,同一线程必须进行一次或多次“获取”,然后再进行“关闭”。

在您的情况下,我什至会考虑只有一个“ get”,并且只要您的线程正在执行其工作单元,就传递该会话:这样一来,发现问题可能会更容易。

关于SO的另一个问题报告了类似的问题:Hibernate4.1.9(最新的最终构建)报告了不支持嵌套事务

您可以在commit()检查之后添加一些代码,以确认交易是否真的完成了(通过调用wasCommitted())。

Javadoc中的引文wasCommitted()

即使成功调用commit(),此方法也可能返回false。例如,如果基于JTA的策略没有启动事务,则它们对no(op)的调用不执行操作。在这种情况下,他们还报告wasCommitted()为假。



 类似资料:
  • 据我所知,当您尝试在提交前一个事务之前开始一个事务时,会发生这种异常。然而,我不明白为什么在我的情况下会有这种例外。 我有一个Web应用程序与以下servlet: 这是我的Compte对象: 这是我的DAO的接口: 这就是它的实施: 另外,这是我的Spring配置: 关联的应用程序。属性文件包含以下行: 最后,我有以下servlet过滤器,从这里开始事务: 这是在网络上映射的。如下所示的xml文件

  • 问题内容: JTA为什么不支持嵌套事务?是因为实现它们的复杂性(我对此表示怀疑)还是某些设计原则? 问题答案: (正如@Piotr Nowicki指出的那样,JTA 确实 允许嵌套事务,但这不是强制性的可选操作。) 为什么?这是无法确定地回答的问题之一,除非您是做出决定时“在房间里”的人之一。 将嵌套事务作为规范的一部分包括在内可能是固有的复杂性。或当时明显的复杂性;即他们不知道他们知道如何做一个

  • 问题内容: 运行removeUserFromConference方法时,遇到以下异常: 道方法: 模型类: 问题答案: 您可能已经开始了一笔交易,并尝试开始另一笔交易而没有提交或回滚上一笔交易。使用程序化事务划分时的惯用法如下: 这很麻烦且容易出错,这就是为什么使用EJB或Spring具有声明式事务如此有用的原因之一。

  • 我有一种情况,我必须提交一部分代码作为它自己的事务。 我已经创建了一个表: 以及plpython3u语言中的函数: 第一种情况: 表中的条目正确:1、2、4 第二种情况: 表中的值未填充 我希望或应该添加到表 中,但出乎意料的是没有插入任何值。我想象函数打开了一个新的子事务,它不应该依赖于父事务。如果我是对的,请告诉我。 Postgres中是否存在自主交易?或者我必须修改我的plpython3u函

  • 问题内容: 避免嵌套查询有多重要。 我一直学会避免像瘟疫一样躲避它们。但是对我来说,它们是最自然的事情。在设计查询时,我首先写的是嵌套查询。然后,我将其转换为联接,有时需要花费很多时间才能正确。而且很少会带来很大的性能提升(有时确实会提高) 他们真的那么糟糕吗?有没有一种方法可以使用没有临时表和文件排序的嵌套查询 问题答案: 这确实取决于我遇到的情况,我可以通过使用子查询来改进一些查询。 我知道的

  • 在Java,有没有一种方法可以避免在调用的每个级别上嵌套null检查,以确保沿途没有阻止下一次调用的null。有没有一个优雅的方法来做这件事? 例如: Objone.ObjTwo.ObjTree.ObjFour.ObjF