如何避免嵌套事务不支持错误? [英] How to avoid nested transactions not supported error?

查看:118
本文介绍了如何避免嵌套事务不支持错误?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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



我的hibernate是4.2.1.Final

$ p $ 消息:
不支持嵌套事务
文件:org / hibernate /engine/transaction/spi/AbstractTransactionImpl.java
行号:152

我的代码

  session = HibernateUtil.getSession(); 
session.getTransaction()。begin(); OR session.beginTransaction();
...做...
session.getTransaction()。commit();
session.close();或者HibernateUtil.closeSession();

HibernateUtil

  import org.hibernate.HibernateException; 
import org.hibernate.Session;
import org.hibernate.SessionFactory;
导入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(** 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);
}

返回会话;


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


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

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

配置 strong>

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

< hibernate-configuration>

< session-factory>

<! - 数据库连接设置 - >
< 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连接池(使用内置) - >
< property name =connection.pool_size> 12< / property>

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

<! - 启用Hibernate的自动会话上下文管理 - >
< property name =current_session_context_class>线程< / property>

<! - 禁用二级缓存 - >
< property name =cache.provider_class>
org.hibernate.cache.NoCacheProvider
< / property>

<! - 将所有执行的SQL回复到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 例外情况;因此,没有回滚

  4. 是否重新引发异常或被忽略? $ b

如果在 begin()之后的待办事项块中存在例外情况,打开并且 ThreadLocal 未被清除。



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



因此,请检查每个 片段对于正确的异常处理:

  final Session session = HibernateUtil.getSession(); 
try {
final Transaction transaction = session.beginTransaction();
尝试{
//真正的工作在这里
transaction.commit();
} catch(Exception ex){
//在这里记录异常
transaction.rollback();
throw ex;
}
}最后{
HibernatilUtil.closeSession();






您可以添加一些 () HibernateUtil.getSession()和 HibernateUtil.closeSession():记录每个访问,包括线程的名称。最后,一个或多个获得相同的线程后面必须跟一个关闭。



在你的情况下,我甚至会考虑只有一个get并且只要你的线程正在完成其工作单元就可以传递会话:这种方式可能更容易找到问题。






SO上有另外一个问题,它报告了类似的问题: Hibernate 4.1.9(最新的最终版本)报告不支持嵌套事务您可以在 commit()之后添加一些代码来检查,如果事务已经(code> wasCommitted())。
$ b $ < wasCommitted():


即使成功调用commit()后,此方法也可以返回false。举例来说,基于JTA的策略如果没有启动事务,就不会调用commit()调用;在那种情况下,他们也会报告wasCommitted()为false。



I need to make sure many concurrent users be able to access the database. Although after each commit I close the session but sometimes my code runs into following error, but when I do the same operation for few times it surpass the error and works.

My hibernate is 4.2.1.Final

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

My Code

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();
    }
  }
}

Configuration

<?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>

解决方案

In your "My code" snippet, there might be some problems:

  1. In case of an exception, there is no finally block to close the session
  2. You are calling session.close(), but this is different from HibernateUtils.closeSession(). So the ThreadLocal is not cleared.
  3. There is no catch block for exceptions; as a consequence there is no rollback.
  4. Do you rethrow exceptions or are they (silently) ignored?

If there is an exception in the "to do" block after begin(), the transaction remains open, and ThreadLocal is not cleared.

Your code may work fine normally, but under high load there might be (SQL lock) timeouts etc., and in this case, once in a while, an exception will be thrown.

So check each snippet for correct exception handling:

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();
}


You could add some "book-keeping" code to HibernateUtil.getSession() and HibernateUtil.closeSession(): Log each access, including the thread's name. Eventually one or multiple "gets" by the same thread must be followed by a "close".

In your case I would even consider to have only one "get", and pass the session around as long as your thread is doing its unit of work: This way it's possibly easier to find the problem.


There is another question on SO which reports a similar problem: Hibernate 4.1.9 (latest final build) reporting `nested transactions not supported.

You could add some code after commit() to check, if the transaction has been really completed (by calling wasCommitted()).

A quote from the Javadoc of wasCommitted():

This method could return false even after successful invocation of commit(). As an example, JTA based strategies no-op on commit() calls if they did not start the transaction; in that case, they also report wasCommitted() as false.

这篇关于如何避免嵌套事务不支持错误?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆