Spring Hibernate:Generic Dao 添加原因 - org.hibernate.TransactionException:不支持嵌套事务

Posted

技术标签:

【中文标题】Spring Hibernate:Generic Dao 添加原因 - org.hibernate.TransactionException:不支持嵌套事务【英文标题】:Spring Hibernate : Generic Dao addition causes - org.hibernate.TransactionException: nested transactions not supported 【发布时间】:2013-05-10 03:57:04 【问题描述】:

我的项目中有一个分层架构。

为了防止冗余,我创建了一个非常基本的通用 dao:

public interface GenericDAO 

   public <T> T getItemById(long id, Class<T> c);

   public <T> int save(T... objectsToSave);

   public <T> int saveOrUpdate(T... objectsToSave);

   public <T> int delete(T... objectsToDelete);
       .
       .

现在我所有的其他 dao 都使用这个通用 dao 作为私有字段,以便使用它的基本方法: 即:

@Repository
public class UserDAOHibernateImpl implements UserDao 

      @Autowired
      private GenericDAO dao;

      @Override
      public int deleteUser(User u) 
        return dao.delete(u);

      

      .
      .
      .

我的服务是这样的:

 @Service
 public class UserServiceHibernateImpl implements UserService 

     @Autowired
     private UserDao userDao;


     @Transactional(readOnly = false)
     public int deleteUser(User u) 
         return userDao.deleteUser(u);
     
         .
         .
         .
 

问题是:

    ApplicationContext ctx = new ClassPathXmlApplicationContext("root-context.xml");
    UserServiceHibernateImpl d = ctx.getBean("userServiceHibernateImpl", UserServiceHibernateImpl.class);   
    User u = d.getUserById(1);

抛出异常:

Exception in thread "main" org.hibernate.TransactionException: nested transactions not supported
at org.hibernate.engine.transaction.spi.AbstractTransactionImpl.begin(AbstractTransactionImpl.java:152)
at org.hibernate.internal.SessionImpl.beginTransaction(SessionImpl.java:1426)
at src.com.plantaware.model.dao.impl.hibernate.GenericDAOHibernateImpl.getItemById(GenericDAOHibernateImpl.java:80)
at src.com.plantaware.model.dao.impl.hibernate.GenericDAOHibernateImpl$$FastClassByCGLIB$$be31a192.invoke(<generated>)
at net.sf.cglib.proxy.MethodProxy.invoke(MethodProxy.java:191)

删除

  @Autowired
  private GenericDAO dao;

我的服务将解决这个问题,但这意味着我必须在我的每个服务上使用冗余代码,这完全没有使用通用 dao 的意义。

任何想法为什么?

顺便说一句:我正在使用 CGLIB 代理,因为没有它我会得到“名为 'X' 的 Bean 必须是 Y 类型,但实际上是 [$Proxy] 类型”异常

谢谢..

【问题讨论】:

【参考方案1】:

您正在将特定于 Spring 的声明式事务管理 (@Transactional) 与特定于 Hibernate 的手动事务管理 (beginTransaction() 等) 混合在一起。

如果你使用@Transactional,你不需要在你的DAO中调用beginTransaction()等,因为Spring已经提供了必要的事务管理。从您的 DAO 中删除手动事务管理代码。

另请参阅:

11. Transaction Management

【讨论】:

你的权利!虽然我没有提到它,但我有 session.beginTransaction();在我的道内。删除它解决了我的问题!谢谢!【参考方案2】:
TransactionException: nested transactions not supported

意味着无论何时你开始一个事务,你都不能在其中开始另一个事务。你首先需要完成它。在这里,不要在 dao 中自动装配 dao

@Repository
public class UserDAOHibernateImpl implements UserDao 

  @Autowired
  private GenericDAO dao; // this is not acceptable.

  @Override
  public int deleteUser(User u) 
    return dao.delete(u);

  

  .
  .
  .

所有业务逻辑都必须在服务层内。 Dao 只针对 db 访问。将所有必要的 dao bean 放入您的服务中。

【讨论】:

那么我应该如何从 UserDAOHibernateImpl 内部调用 GenericDAO 呢?

以上是关于Spring Hibernate:Generic Dao 添加原因 - org.hibernate.TransactionException:不支持嵌套事务的主要内容,如果未能解决你的问题,请参考以下文章

尝试使用 EhCache 使用 Spring 和扩展 Hibernate 的 JpaRepository 的自定义 GenericDao 接口

不使用 Spring 获取 EntityManager

spring Transactional

Generic Hibernate DAO

Hibernate Generic DAO - 测试生成的 SQL 是不是正确

Spring和Hibernate的注解整合 hibernate3和hibernate4/5的区别