我需要确保许多并发用户能够访问数据库。虽然每次提交后我都会关闭会话,但有时我的代码会遇到以下错误,但当我多次执行相同的操作时,它会超过错误并工作。
我的休眠是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();
Hibernate Util
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>
在您的"我的代码"片段中,可能存在一些问题:
- 在出现异常的情况下,没有
finally
块来关闭会话 - 您正在调用
session.close()
,但这与HibernateUtils.closeSession()
不同。因此ThreadLocal
不被清除 - 没有针对异常的
catch
块;因此不存在CCD_ 6 - 您是重新抛出异常,还是(静默地)忽略了它们
如果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"后面必须跟一个"close"。
在你的情况下,我甚至会考虑只有一个"get",只要你的线程在做它的工作单元,就可以传递会话:这样可能更容易找到问题。
SO上还有另一个问题,它报告了类似的问题:Hibernate 4.1.9(最新的最终版本)报告"不支持嵌套事务"。
如果事务已经真正完成(通过调用wasCommitted()
),您可以在commit()
之后添加一些代码进行检查。
引用wasCommitted()
的Javadoc:
即使在成功调用commit()之后,此方法也可能返回false。例如,基于JTA的策略如果没有启动事务,就不会调用-op-on-commit();在这种情况下,他们还将wasCommitted()报告为false。
您可能已经开始了一个事务,并试图在没有提交或回滚前一个事务的情况下开始另一个事务。使用程序化事务划分时的习惯用法如下:
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>
在代码中使用session.beginTransaction()而不是session.getTransaction(。您需要开始新的工作单元,因此beginTransaction将开始一个新的事务。所以你的代码看起来像:
session = HibernateUtil.getSession();
Transaction transaction = session.beginTransaction();
... to do ....
transaction.commit();
单击此处获取有关beginTransaction()的更多信息;方法
我认为这将解决你的问题。如果问题仍然存在,请告诉我。
我也面临同样的问题,我通过放入tr.commit()解决了我的问题;函数。只有当您启动任何事务而没有关闭前一个事务时,才会发生这种情况。
session = HibernateUtil.getSession();
session.getTransaction().begin(); OR session.beginTransaction();
... to do ....
session.getTransaction().commit();
session.close(); OR HibernateUtil.closeSession();
看起来你们也犯了同样的错误。
我遇到了类似的问题:org.hubinate.TransactionException:嵌套事务不支持
就我而言,我打开了一个会话并尝试保存。在没有提交的情况下,我调用了另一个方法并调用了session.beginTransaction();所以它抛出了错误。为了避免,我将会话对象作为方法参数发送,并只调用session.save,而不是再次执行begin。实际使用了会话对象。它对我有用!