I have a problem with transactions in that annotating a service that calls a DAO with #Transactional throws an exception stating that the Session is not open. The only way I can get it working is by annotating the DAO with #Transactional. What on earth can be happening?
This is what I'd like to do but doesn't work:
class CustomerService {
private CustomerDao dao;
#Transactional
public void foo() {
int customerId = dao.getCustomer("fred");
}
}
class CustomerDao {
private HibernateTemplate hibernateTemplate;
public int getCustomer(String name) {
String sql = "SELECT {m.*} from Customers {m} where name=:name";
Query qry = getSession().createSQLQuery(sql).addEntity("m", Customer.class);
qry.setParameter("name", name);
qry.setCacheable(false);
List<Customer> list = qry.list();
return list.iterator().next().getId();
}
private Session getSession() {
return hibernateTemplate.getSessionFactory().getCurrentSession();
}
}
This is what I'm doing instead but would rather not have to:
class CustomerService {
private CustomerDao dao;
public Customer(CustomerDao dao) {
this.dao = dao;
}
public void foo() {
int customerId = dao.getCustomer("fred");
}
}
class CustomerDao {
private HibernateTemplate hibernateTemplate;
#Transactional
public int getCustomer(String name) {
String sql = "SELECT {m.*} from Customers {m} where name=:name";
Query qry = getSession().createSQLQuery(sql).addEntity("m", Customer.class);
qry.setParameter("name", name);
qry.setCacheable(false);
List<Customer> list = qry.list();
return list.iterator().next().getId();
}
private Session getSession() {
return hibernateTemplate.getSessionFactory().getCurrentSession();
}
}
The problem seems to be caused by the CustomerService being instantiated inside the constructor of a wrapper class, where the wrapper is declared in the Spring xml context file:
class AllServices {
private final CustomerService customerService;
private final OrderService orderService;
#Autowired
public AllServices(CustomerDao customerDao, OrderDao orderDao) {
this.customerService = new CustomerService(customerDao);
this.orderService = new OrderService(orderDao);
}
public CustomerService getCustomerService() {
return this.customerService;
}
public OrderService getOrderService() {
return this.orderService;
}
}
The spring file looks like this:
<context:annotation-config />
<import resource="classpath:db-spring-conf.xml"/>
<bean id="allServices" class="myPackage.AllServices" />
and the db-spring-conf:
<bean id="editorDatasource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<property name="driverClassName" value="com.mysql.jdbc.Driver" />
<property name="url" value="${versioning.db}" />
<property name="username" value="${versioning.user}" />
<property name="password" value="${versioning.pass}" />
</bean>
<tx:annotation-driven transaction-manager="editorTransactionManager"/>
<bean id="editorSessionFactory" class="org.springframework.orm.hibernate3.annotation.AnnotationSessionFactoryBean">
<property name="dataSource" ref="editorDatasource"/>
<property name="exposeTransactionAwareSessionFactory">
<value>true</value>
</property>
<property name="annotatedClasses">
<list>
<value>myPackage.Order</value>
</list>
</property>
<property name="mappingResources">
<list>
<value>mappings/customer.hbm.xml</value>
</list>
</property>
<property name="hibernateProperties">
<props>
<prop key="hibernate.dialect">org.hibernate.dialect.MySQLDialect</prop>
<prop key="hibernate.show_sql">true</prop>
<prop key="hibernate.hbm2ddl.auto">validate</prop>
<!-- Enable Query Cache -->
<prop key="hibernate.cache.use_query_cache">false</prop>
<!-- Enable 2nd Level Cache -->
<prop key="hibernate.cache.use_second_level_cache">false</prop>
<prop key="hibernate.connection.autocommit">false</prop>
<prop key="hibernate.current_session_context_class">org.springframework.orm.hibernate3.SpringSessionContext</prop>
</props>
</property>
</bean>
<bean id="editorHibernateTemplate" class="org.springframework.orm.hibernate3.HibernateTemplate">
<property name="sessionFactory" ref="editorSessionFactory"/>
</bean>
<bean id="editorTransactionManager" class="org.springframework.orm.hibernate3.HibernateTransactionManager">
<property name="sessionFactory" ref="editorSessionFactory" />
</bean>
<!-- DAOs -->
<bean id="customerDao" class="myPackage.CustomerHibernateDao" />
<bean id="orderDao" class="myPackage.OrderHibernateDao" />
I've now moved the instantiation of CustomerService up to the Spring config file and everything works a treat. Do all classes using #Transactional have to be in the context file? Also in order to make it work I had to create an interface for CustomerService to prevent an exception whilst loading the context file - Could not generate CGLIB subclass of class
So, you identified the cause of problem - Spring's #Transactional support is an aspect, and aspects in Spring are applied only to the components managed by the Spring contrainer (though it can be changed, but it's an advanced feature for complex cases).
If you don't like declaring services in XML, you may take a look at other options to delcare Spring-managed components:
Classpath scanning
Java-based configuration (since Spring 3.x)
Regarding the problem with CGLIB proxies see 7.6 Proxying mechanisms - probably you don't have CGLIB implementation in the classpath.
Related
In our project, we are trying to get code that is currently deployed on WebSphere working on Liberty instead.
After receiving a message an MDB calls a method in a service which inserts the data into a DB2 database.
The problem is that when flush is called, we get the following errors in the log:
javax.persistence.TransactionRequiredException: no transaction is in progress
at org.hibernate.jpa.spi.AbstractEntityManagerImpl.checkTransactionNeeded(AbstractEntityManagerImpl.java:1136) ~[hibernate-entitymanager-5.1.3.Final.jar:5.1.3.Final]
at org.hibernate.jpa.spi.AbstractEntityManagerImpl.flush(AbstractEntityManagerImpl.java:1297) ~[hibernate-entitymanager-5.1.3.Final.jar:5.1.3.Final]
[ERROR ] WLTC0017E: Resources rolled back due to setRollbackOnly() being called.
There are no other errors, like SQL query not being correct or something like that.
Since this code is working fine in WebSphere, I'm wondering if there is something wrong in the configuration or if Liberty does something different in handling transactions.
Below are the relevant pieces of code and configuration:
#Service
public class IdentificationService implements IIdentificationService {
#Autowired
private IIdentificationDAO identificationDAO;
#Transactional
public Identification insertIdentificationData(RequestForIdentificationRequest request, String referenceNumber) {
final Identification identification = new Identification();
...
identificationDAO.create(identification);
LOGGER.debug("Identification record saved with id: {}", identification.getId());
return identification;
}
}
#Repository
public class IdentificationDAO extends BaseDAO implements IIdentificationDAO {
#Override
public void create(final Identification identification) {
insertRecord(identification);
}
}
public abstract class BaseDAO
{
#PersistenceContext(name = "UserData", unitName = "UserData")
private EntityManager em;
/**
* #param record
*/
public <T> void insertRecord(final T record)
{
em.persist(record);
em.flush();
}
}
public class Identification implements Serializable {
#Id
#Column(name = "ID")
#GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "sequenceGenerator")
#SequenceGenerator(sequenceName = "IDENTIFICATION_SEQ", name = "sequenceGenerator", allocationSize = 1)
private Long id;
...
}
applicationContext.xml
<jee:jndi-lookup id="userDataSource" jndi-name="jdbc/userdataDB" />
<bean id="userDataEntityManagerFactory" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
<property name="persistenceUnitName" value="UserData" />
<property name="persistenceXmlLocation" value="classpath:persistence-userdata.xml" />
<property name="dataSource" ref="userDataSource" />
<property name="jpaVendorAdapter">
<bean class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter">
<property name="showSql" value="true" />
<property name="generateDdl" value="false" />
<property name="databasePlatform" value="org.hibernate.dialect.DB2Dialect" />
</bean>
</property>
<property name="loadTimeWeaver">
<bean class="org.springframework.instrument.classloading.InstrumentationLoadTimeWeaver" />
</property>
</bean>
<bean id="transactionManager" class="org.springframework.orm.jpa.JpaTransactionManager">
<property name="entityManagerFactory" ref="userDataEntityManagerFactory" />
</bean>
server.xml
<library id="DB2JCCLib">
<fileset dir="/etc/liberty/jdbc" includes="db2jcc4.jar, db2jcc_license_cisuz.jar, db2jcc_license_cu.jar"/>
</library>
<dataSource id="UserDB" jndiName="jdbc/userdataDB" type="javax.sql.XADataSource"
isolationLevel="TRANSACTION_READ_COMMITTED">
<jdbcDriver libraryRef="DB2JCCLib" javax.sql.XADataSource="com.ibm.db2.jcc.DB2XADataSource"/>
<properties.db2.jcc serverName="${datasource.userdb.serverName}" portNumber="${datasource.userdb.portNumber}"
databaseName="${datasource.userdb.databaseName}"
user="user" password="password"/>
</dataSource>
UPDATE: The problem turned out to be multiple transaction manager beans (named the same) in the configuration pointing at different databases.
Giving them unique names and referring to them explicitly in the Transactional annotation did the trick
I was trying to do generic way of implementation of DAO and I followed as per the Article
Following are my genericDaoImpl class
#SuppressWarnings("unchecked")
#Repository
public abstract class GenericDaoImpl<E, K extends Serializable>
implements GenericDao<E, K> {
#Autowired
private SessionFactory sessionFactory;
protected Class<? extends E> daoType;
/**
* By defining this class as abstract, we prevent Spring from creating
* instance of this class If not defined as abstract,
* getClass().getGenericSuperClass() would return Object. There would be
* exception because Object class does not hava constructor with parameters.
*/
public GenericDaoImpl() {
Type t = getClass().getGenericSuperclass();
ParameterizedType pt = (ParameterizedType) t;
daoType = (Class) pt.getActualTypeArguments()[0];
}
protected Session currentSession() {
return sessionFactory.getCurrentSession();
}
#Override
public void add(E entity) {
currentSession().save(entity);
}
#Override
public void saveOrUpdate(E entity) {
currentSession().saveOrUpdate(entity);
}
#Override
public void update(E entity) {
currentSession().saveOrUpdate(entity);
}
#Override
public void remove(E entity) {
currentSession().delete(entity);
}
#Override
public E find(K key) {
return (E) currentSession().get(daoType, key);
}
#Override
public List<E> getAll() {
return currentSession().createCriteria(daoType).list();
}
}
GENERICDAO
public interface GenericDao<E,K> {
public void add(E entity) ;
public void saveOrUpdate(E entity) ;
public void update(E entity) ;
public void remove(E entity);
public E find(K key);
public List<E> getAll() ;
}
SERVICE CLASS
#Service
public class test {
#Autowired
TestPlanDao testPlanDao;
#Transactional(propagation = Propagation.REQUIRED)
public int saveTestPlan()
{
try
{
TestPlan tp=new TestPlan();
tp.setTestplan_version(1);
testPlanDao.saveTestPlan(tp);
logger.info("testplan saved");
return 1;
}
catch(Exception e)
{
e.printStackTrace();
logger.error(e.getMessage(),e);
return 0;
}
}
This is my daoImpl
#Repository
public class TestPlanDaoImpl extends GenericDaoImpl<TestPlan, Integer> implements TestPlanDao{
#Override
#Transactional
public void saveTestPlan(TestPlan tp) {
// TODO Auto-generated method stub
add(tp);
}
hibernate configuration xml
<bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource"
destroy-method="close">
<property name="driverClassName" value="com.mysql.jdbc.Driver" />
<property name="url" value="jdbc:mysql://${mysqlHost}/${mysqldatabase}" />
<property name="username" value="${mysqlUserName}" />
<property name="password" value="${mysqlPassword}" />
<property name="removeAbandoned" value="true" />
<property name="initialSize" value="20" />
<property name="maxActive" value="30" />
<property name="maxIdle" value="-1" />
<property name ="testOnBorrow" value="true"/>
<property name ="validationQuery" value="SELECT 1"/>
</bean>
<bean id="sessionFactoryConf"
class="org.springframework.orm.hibernate4.LocalSessionFactoryBean">
<property name="dataSource" ref="dataSource" />
<property name="annotatedClasses">
<list>
<value>com.test.model.TestPlan</value>
</list>
</property>
<property name="hibernateProperties">
<props>
<prop key="hibernate.dialect">org.hibernate.dialect.MySQLDialect</prop>
<prop key="hibernate.transaction.auto_close_session">true</prop>
<prop key="hibernate.hbm2ddl.auto">update</prop>
</props>
</property>
</bean>
I am not able to find the cause of
org.hibernate.HibernateException: No Session found for current thread
at org.springframework.orm.hibernate4.SpringSessionContext.currentSession(SpringSessionContext.java:106)
at org.hibernate.internal.SessionFactoryImpl.getCurrentSession(SessionFactoryImpl.java:988)
Did you try removing the following property :
<prop key="hibernate.transaction.auto_close_session">true</prop>
I believe that Hibernate will close the session too soon and resulting in your error. Since you use Spring TransactionManager, let it close the session.
you need to add following code in your hibernate configuration xml file
<tx:annotation-driven transaction-manager="transactionManager" />
<bean id="transactionManager" class="org.springframework.orm.hibernate4.HibernateTransactionManager">
<!-- property should be wired with a Hibernate SessionFactory in your case it is sessionFactoryConf -->
<property name="sessionFactory" ref="sessionFactoryConf" />
</bean>
You have to remove the #Transactional annotation from the Repository method , use only the #Transactional annotation on the service layer method.
#Repository
public class TestPlanDaoImpl extends GenericDaoImpl<TestPlan, Integer> implements TestPlanDao{
#Override
#Transactional //Remove annotation from here
public void saveTestPlan(TestPlan tp) {
// TODO Auto-generated method stub
add(tp);
}
Remove #Transactional annotation from function and use it on the class level.
<bean id="transactionManager"
class="org.springframework.orm.hibernate3.HibernateTransactionManager">
<property name="sessionFactory" ref="sessionFactoryConf" />
</bean>
This happens when you try to save changes on a Business Object after a transaction has already finished.
I think you should take a look to Spring Data JPA ? It has a lot more to offer than a generic DAO.
I have the following bean configuration :
<bean class="com.MyFactoryBean" depends-on="otherBean" scope="prototype">
<property name="dataSource" ref="defaultDataSource"/>
<property name="myCustomProperties">
<props>
<prop key="test">HELLO</prop>
</props>
</property>
</bean>
And then my class
public class MyFactoryBean {
public MyFactoryBean(final DataSource dataSource) {
// myConstructor
}
public void setMyCustomProperties(final Properties myCustomProperties) {
System.out.println("Hi");
}
}
While the dataSource is being passed to the constructor, the customProperties are not.
Scope prototype means that every time you ask spring using getBean or dependency injection, for an instance it will create a new instance.
Missing default constructor.
Class
public class MyFactoryBean {
private DataSource dataSource;
private Properties myCustomProperties;
public void setDataSource(final DataSource dataSource) {
this.dataSource = dataSource;
}
public void setMyCustomProperties(final Properties myCustomProperties) {
this.myCustomProperties = myCustomProperties;
}
}
XML config
<bean class="com.MyFactoryBean" depends-on="otherBean">
<property name="dataSource" ref="defaultDataSource"/>
<property name="myCustomProperties">
<props>
<prop key="test">HELLO</prop>
</props>
</property>
</bean>
Furthermore if you want use an hybrid solution you can use your Class and below configuration.
<bean class="com.MyFactoryBean" depends-on="otherBean">
<constructor-arg ref="defaultDataSource" />
<property name="myCustomProperties">
<props>
<prop key="test">HELLO</prop>
</props>
</property>
</bean>
The issue was that this bean was not actually being loaded but it was being constructed manually from another location
I've got this web service that basically queries the database and returns all persisted entities. For testing purposes, I've created a TestDataManager that persists 2 example entities after Spring context is loaded (BTW, I'm using JAX-WS, Spring, Hibernate and HSQLDB).
My TestDataManager looks like this:
#Component
public class TestDataManager {
#Resource
private SessionFactory sf;
#PostConstruct
#Transactional(readOnly = false, propagation = Propagation.REQUIRES_NEW)
public void insertTestData(){
sf.openSession();
sf.openSession().beginTransaction();
sf.openSession().persist(new Site("site one"));
sf.openSession().persist(new Site("site two"));
sf.openSession().flush();
}
}
My JAX-WS endpoint looks like this:
#WebService
public class SmartBrickEndpoint {
#Resource
private WebServiceContext context;
public Set<Site> getSitesForUser(String user){
return getSiteService().findByUser(new User(user));
}
private ISiteService getSiteService(){
ServletContext servletContext = (ServletContext) context.getMessageContext().get("javax.xml.ws.servlet.context");
return (ISiteService) BeanRetriever.getBean(servletContext, ISiteService.class);
}
}
This my Service class:
#Component
#Transactional(readOnly = true)
public class SiteService implements ISiteService {
#Resource
private ISiteDao siteDao;
#Override
public Set<Site> findByUser(User user) {
return siteDao.findByUser(user);
}
}
This is my DAO:
#Component
#Transactional(readOnly = true)
public class SiteDao implements ISiteDao {
#Resource
private SessionFactory sessionFactory;
#Override
public Set<Site> findByUser(User user) {
Set<Site> sites = new LinkedHashSet<Site>(sessionFactory.getCurrentSession().createCriteria(Site.class).list());
return sites;
}
}
This is my applicationContext.xml:
<context:annotation-config />
<context:component-scan base-package="br.unirio.wsimxp.dao"/>
<context:component-scan base-package="br.unirio.wsimxp.service"/>
<context:component-scan base-package="br.unirio.wsimxp.spring"/>
<bean id="applicationDS" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<property name="driverClassName" value="org.hsqldb.jdbcDriver"/>
<property name="url" value="jdbc:hsqldb:file:sites"/>
</bean>
<bean id="sessionFactory"
class="org.springframework.orm.hibernate3.annotation.AnnotationSessionFactoryBean">
<property name="dataSource" ref="applicationDS" />
<property name="configLocation">
<value>classpath:hibernate.cfg.xml</value>
</property>
<property name="hibernateProperties">
<props>
<prop key="hibernate.dialect">org.hibernate.dialect.HSQLDialect</prop>
<prop key="hibernate.show_sql">true</prop>
<prop key="hibernate.format_sql">true</prop>
<prop key="hibernate.connection.release_mode">on_close</prop>
<!--<prop key="hibernate.current_session_context_class">thread</prop>-->
<prop key="hibernate.query.factory_class">org.hibernate.hql.classic.ClassicQueryTranslatorFactory</prop>
<prop key="hibernate.hbm2ddl.auto">create-drop</prop>
</props>
</property>
</bean>
<bean id="transactionManager" class="org.springframework.orm.hibernate3.HibernateTransactionManager">
<property name="sessionFactory" ref="sessionFactory" />
</bean>
<tx:annotation-driven transaction-manager="transactionManager" />
This is what's going on now:
when the app is deployed, TestDataManager#insertTestData kicks-in (due to #PostConstruct) and persist does not raise any exception. I should have 2 entities in the DB by now.
Afterwards, I invoke the endpoint by a SOAP client, and the request goes all the way up to the DAO. The Hibernate invocation does not raise any exception, but the returned list is empty.
The odd thing is, in TestDataManager, if I switch from sf.openSession() to sf.getCurrentSession(), I get an error message: "No Hibernate Session bound to thread, and configuration does not allow creation of non-transactional one here".
What I am doing wrong here? Why is the query "not seeing" the persisted entities? Why do I need to invoke sf.openSession() on TestDataManager although it's annotated with #Transactional?
I have done some tests with hibernate.current_session_context_class=thread in application.xml, but then I just switch problems in each class. I'd like not needing to manually invoke sf.openSession() and leave that for Hibernate to take care.
Thanks a lot for any help!
I think you need to commit the transaction on insertTestData:
#PostConstruct
#Transactional(readOnly = false, propagation = Propagation.REQUIRES_NEW)
public void insertTestData(){
Session session = sf.openSession();
session.persist(new Site("site one"));
session.persist(new Site("site two"));
session.flush();
session.close();
}
(I use hibernate in jpa mode)
I think your transactional annotations are not intercepted properly. Have you specified the HibernateVendorAdapter? In jpa+hibernate the integration is not fully setuped without it! Most likely you are missing this declaration.
After you should be able to autowire directly the Session instead of the Factory.
As a side note. If you use opensession in your code at least call it only once and keep the session in a variable. Else you are always opening a new one on each call i believe.
#PostConstruct
public void insertTestData(){
Obejct o = new TransactionTemplate(transactionManager).execute(new TransactionCallback() {
public Object doInTransaction(TransactionStatus status) {
//Your code here
}
});
}
source: http://forum.springsource.org/showthread.php?58337-No-transaction-in-transactional-service-called-from-PostConstruct&p=194863#post194863
So, I read that the best place to put the #Transactional annotation was outside the DAO classes which contains the db access methods, like in a service class which use those methods.
Now, the problem is, once I've already remove this annotations from the DAO classes, I launch the DAO test methods and the aforementioned exception raised. I put back the annotations in the DAO classes and this exception doesn't raises anymore.
Then my question is: how can I clear my DAOs of this annotations and still have my tests working?
Let's add some code:
DAO class
public class UserDAO extends IDAO implements IUserDAO {
#Override
//#Transactional(readOnly=true)
public User get(int idUser) {
return (User) currentSession().get(User.class,idUser);
}}
IDAO Class
public abstract class IDAO {
protected SessionFactory sessionFactory;
public void setSessionFactory(SessionFactory sessionFactory) {
this.sessionFactory = sessionFactory;
}
public Session currentSession()
{
return sessionFactory.getCurrentSession();
}
}
Test class
#RunWith(SpringJUnit4ClassRunner.class)
#ContextConfiguration(locations = { "classpath:META-INF/spring/app-context.xml" })
public class UserDAOTest extends AbstractJUnit4SpringContextTests {
#Autowired
private IUserDAO userDAO;
#Test
public void testGetUser() throws Exception {
User user = userDAO.get(2);
assertNotNull(user);
}
}
app-config
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context"
xmlns:tx="http://www.springframework.org/schema/tx" xmlns:jdbc="http://www.springframework.org/schema/jdbc"
xsi:schemaLocation="
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.1.xsd
http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-3.1.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.1.xsd">
<bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource"
destroy-method="close">
<property name="driverClassName" value="com.mysql.jdbc.Driver" />
<property name="url"
value="jdbc:mysql://localhost:3306/waldb" />
<property name="username" value="user" />
<property name="password" value="password" />
</bean>
<bean id="sessionFactory"
class="org.springframework.orm.hibernate4.LocalSessionFactoryBean">
<property name="dataSource" ref="dataSource" />
<property name="annotatedClasses">
<list>
<value>com.wal.serverside.persistence.domain.User</value>
</list>
</property>
<property name="hibernateProperties">
<props>
<prop key="hibernate.dialect">org.hibernate.dialect.MySQL5Dialect</prop>
<prop key="hibernate.hbm2ddl.auto">update</prop>
</props>
</property>
</bean>
<bean id="transactionManager"
class="org.springframework.orm.hibernate4.HibernateTransactionManager">
<property name="sessionFactory" ref="sessionFactory" />
</bean>
<bean id="userDAO" class="com.wal.serverside.persistence.DAO.UserDAO">
<property name="sessionFactory" ref="sessionFactory" />
</bean>
<tx:annotation-driven transaction-manager="transactionManager" />
<context:component-scan base-package="com.wal.serverside.persistence" />
</beans>
Gosh, how much stupid can I be?
My test class didn't extend from AbstractTransactionalJUnit4SpringContextTests, so there were nor transaction nor session inside my tests.
This fixed it all:
#RunWith(SpringJUnit4ClassRunner.class)
#ContextConfiguration(locations = { "classpath:META-INF/spring/app-context.xml" })
#TransactionConfiguration(transactionManager="transactionManager", defaultRollback=false)
#Transactional
public class UserDAOTest extends AbstractTransactionalJUnit4SpringContextTests {
#Autowired
private IUserDAO userDAO;
public void setUserDAO(IUserDAO userDAO) {
this.userDAO = userDAO;
}
#Test
public void testGetUser() throws Exception {
User user = userDAO.get(2);
assertNotNull(user);
}
}
Try to put not only #Transactional annotaition on your test class but also #TransactionConfiguration(transactionManager="transactionManager", defaultRollback=false). Where you explicitly set the name of the transaction manager that you have defined in xml.
#RunWith(SpringJUnit4ClassRunner.class)
#ContextConfiguration(locations = { "classpath:META-INF/spring/app-context.xml" })
#TransactionConfiguration(transactionManager="transactionManager", defaultRollback=false)
#Transactional(propagation=Propagation.REQUIRED, rollbackFor={Exception.class})
public class UserDAOTest {
...
}
Also transaction will not work if you explicitly create the application context in your test method and then get the bean from it:
ApplicationContext appContext = new ClassPathXmlApplicationContext(...);
SomeDAO someDAO = (SomeDAO) appContext.getBean(...);
instad of inhjecting it.
But I see this is not your case.