异常名称: org.hibernate.TransactionException: nested transactions not supported
异常分析:You probably have begun a transaction, and trying to begin another one without having committed or rollbacked the previous one.(from stackoverflow.com)
简单得说就是在使用Hbernate框架时,在开启新的transaction时,原来的transaction事务却没有提交或者撤销,导致出现该异常。 我在这里加上一种情况,提交Transaction事务与开启的不一致![/size]
解决方案:第一种:就如大多数偷懒的做法,主动提交事务,去掉以下两行代码。
session.beginTransation();
session.getTransaction().commit();
例如:
public void addUser(User user){
Session session = HibernateUtil.getSession();
try {
session.save(user);
} catch (Exception e) {
e.printStackTrace();
}
}
其实Hibernate本身是不具备Transaction处理功能的,Hibernate的Transaction实际上是底层的JDBC Transaction的封装,或者是JTA Transaction的封装。
#hibernate.transaction.factory_class net.sf.hibernate.transaction.JTATransactionFactory
#hibernate.transaction.factory_class net.sf.hibernate.transaction.JDBCTransactionFactory
如果你什么都不配置,默认情况下使用JDBCTransaction。
可以看Hibernate中关于JDBCTransactionFactory的部分
package org.hibernate.engine.transaction.internal.jdbc;
public class JdbcTransaction extends AbstractTransactionImpl {
@Override
protected void doBegin() {
...
if ( wasInitiallyAutoCommit ) {
managedConnection.setAutoCommit( false );
}
...
}
}
转换到Transaction事务处理:当我们什么都不做时,直接使用save()方法(对于所有CURD操作试用), Hibernate使用的是session.setAutoCommit(true),对应到JDBC,就是connection.setAutoCommit(true);数据库就帮你给把事务代理了。
但一旦使用session.beginTransation()或者session.getTransation().begin(), Hibernate 将自动提交事物关闭:session.setAutoCommit(false),这是必须手动提交事务。
所以就引申出第二种解决方案:手动提交事务
在有自动提交事务的情况下,为什么要手动提交事务呢?主要是针对以后的高并发问题,手动提交事务可以更有效的控制高并发可能出现的各种问题。
其实,大多数是手动提交事务,但是代码写的不准确,比如说我。下面是不规范的代码
public void addUser(User user){ //错误代码
Session session = HibernateUtil.getSession();
session.beginTransaction();
try {
session.save(user);
session.getTransaction().commit();
} catch (Exception ef) {
ef.printStackTrace();
}
}
规范的写法是下面这种:保证是同一个事务。
]public void addUser(User user){ //正确写法
Session session = HibernatUtil.getSession();
Transaction tx = session.beginTransaction();
try {
session.save(user);
tx.commit(); //事物必须提交
} catch (Exception ef) {
if (null != tx) {
tx.rollback();//撤销事务
ef.printStackTrace();
}
}
}