如何避免嵌套事务不支持错误?
Posted
技术标签:
【中文标题】如何避免嵌套事务不支持错误?【英文标题】:How to avoid nested transactions not supported error? 【发布时间】:2013-07-09 07:11:07 【问题描述】:我需要确保许多并发用户能够访问数据库。虽然每次提交后我都会关闭会话,但有时我的代码会遇到以下错误,但是当我多次执行相同的操作时,它会超过错误并且可以工作。
我的休眠是 4.2.1.Final
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>
【问题讨论】:
对我来说看起来像是种族危险;编写自己的ThreadLocal
范围事务有很多陷阱。我强烈建议您不要编写自己的会话管理代码,使用提供的CurrentSessionContext
实现之一。
你知道任何例子吗?
可能以the documentation开头。
看看docs.jboss.org/hibernate/orm/3.3/reference/en/html/…
您使用的是哪个版本的 Hibernate、数据库和应用程序服务器?有 JTA 事务管理器吗?您的“我的代码” sn-p 根本不处理异常。即使成功,session.close()
也不会重置ThreadLocal
变量,这与HibernateUtils.closeSession()
不同。你检查过question吗?
【参考方案1】:
在你的“我的代码”sn-p中,可能有一些问题:
-
如果出现异常,没有
finally
块可以关闭会话
您正在呼叫session.close()
,但这与HibernateUtils.closeSession()
不同。所以ThreadLocal
没有被清除。
没有catch
异常块;因此没有rollback
。
您是重新抛出异常还是(默默地)忽略它们?
如果begin()
之后的“待办事项”块中有异常,则事务保持打开状态,ThreadLocal
不会被清除。
您的代码可能正常工作,但在高负载下可能会出现(SQL锁)超时等,在这种情况下,偶尔会抛出异常。
所以检查each sn-p 是否正确 异常处理:
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 的另一个问题报告了类似的问题:Hibernate 4.1.9 (latest final build) reporting `nested transactions not supported。
您可以在commit()
之后添加一些代码来检查事务是否真的完成(通过调用wasCommitted()
)。
引用wasCommitted()
的Javadoc:
即使在成功调用 commit() 后,此方法也可能返回 false。例如,基于 JTA 的策略 no-op on commit() 调用,如果它们没有启动事务;在这种情况下,他们还将 wasCommitted() 报告为 false。
【讨论】:
感谢您的回答,您认为我目前的设置是否足以应付大量用户? @Mir Moorido 您的主要问题解决了吗?您还没有选择答案。无论如何,很难判断您的设置是否适合大量用户。您应该使用不同数量的并发用户设置测试。 我已经在我的代码中使用了它,但没有太多时间测试它,将测试它并告诉你谢谢 @MirMoorido 感谢第二次赏金,确实非常高尚。我很好奇哪种措施/行动对您有帮助? 不用担心,你应得的,它不再显示相同的错误,我相信这是因为正确的异常处理和使用 HibernateUtil.closesession() 无论如何谢谢。【参考方案2】:您可能已经开始了一个事务,并试图在没有提交或回滚前一个事务的情况下开始另一个事务。使用程序化事务划分时的习惯用法如下:
Transaction transaction = null;
try
session = HibernateUtil.getSession();
transaction = session.beginTransaction();
... to do ....
transaction.commit();
catch (RuntimeException e)
transaction.rollback();
throw e;
在您的 Hibernate.cfg.xml 中添加以下属性
<prop key="hibernate.current_session_context_class">thread</prop>
【讨论】:
感谢问题已更新 我想我需要,你知道它的优缺点吗? Hibernate 4+ 这个属性带来了另一个噩梦:***.com/questions/18832889/…【参考方案3】:在您的代码中使用 session.beginTransaction() 而不是 session.getTransaction().begin()。您需要开始一个新的工作单元,因此 beginTransaction 将开始一个新事务。 所以你的代码看起来像:
session = HibernateUtil.getSession();
Transaction transaction = session.beginTransaction();
... to do ....
transaction.commit();
点击Here获取更多关于beginTransaction()的信息;方法。
我认为这将解决您的问题。如果问题仍然存在,请告诉我。
【讨论】:
【参考方案4】:我遇到了同样的问题,我通过 tr.commit(); 解决了我的问题每次交易后的功能。 只有当您开始任何交易而不关闭之前的交易时才会发生这种情况。
session = HibernateUtil.getSession();
session.getTransaction().begin(); OR session.beginTransaction();
... to do ....
session.getTransaction().commit();
session.close(); OR HibernateUtil.closeSession();
看起来你也犯了同样的错误。
【讨论】:
【参考方案5】:我遇到了类似的问题: org.hibernate.TransactionException:不支持嵌套事务
就我而言,我打开了一个会话并尝试保存 .没有提交,我调用了另一个方法并调用了 session.beginTransaction(); 所以它抛出错误。 为了避免,我将会话对象作为方法参数发送,并且只调用 session.save 而不是再次执行 begin。实际使用了会话对象。 它对我有用!
【讨论】:
以上是关于如何避免嵌套事务不支持错误?的主要内容,如果未能解决你的问题,请参考以下文章
org.hibernate.TransactionException:获取数据时不支持嵌套事务
Hibernate 4.1.9(最新的最终版本)报告“不支持嵌套事务”
Hibernate org.hibernate.TransactionException:jaxrs 不支持嵌套事务
Hibernate + Jersey + Jackson 随机获得“org.hibernate.TransactionException:不支持嵌套事务”
Spring Hibernate:Generic Dao 添加原因 - org.hibernate.TransactionException:不支持嵌套事务