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..
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: