Spring Hibernate : Generic Dao addition causes - org.hibernate.TransactionException: nested transactions not supported

StackOverflow https://stackoverflow.com/questions/16567415

Question

I have a layered architecture in my project.

in order to prevent redundancy i created a very basic generic 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);
       .
       .
}

now all my other dao's uses this generic dao as a private field in order to use its basic methods: i.e:

@Repository
public class UserDAOHibernateImpl implements UserDao {

      @Autowired
      private GenericDAO dao;

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

      }

      .
      .
      .
}

My services are like this :

 @Service
 public class UserServiceHibernateImpl implements UserService {

     @Autowired
     private UserDao userDao;


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

Problem is that:

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

throws the exception:

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)

Removing the

  @Autowired
  private GenericDAO dao;

from my service will solve this, but that mean ill have to use redundant code on each one of my services, that's missing the point completely of using a generic dao.

any ideas why?

BTW: I'm using CGLIB proxy since without that I'm getting the "Bean named 'X' must be of type Y but was actually of type [$Proxy]" exception

thanks..

Était-ce utile?

La solution

You are mixing Spring-specific declarative transaction management (@Transactional) with Hibernate-specific manual transaction management (beginTransaction(), etc).

If you use @Transactional you don't need to call beginTransaction(), etc in your DAO, because necessary transaction management is already provided by Spring. Remove manual transaction management code from your DAO.

See also:

Autres conseils

TransactionException: nested transactions not supported

means that whenever you start a transaction, you cannot start another inside it. You first need to finish it. Here, don't autowire dao inside 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);

  }

  .
  .
  .

}

All business logic must be inside service layer. Dao aims only db access. Put all necessary dao beans inside your services.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top