Spring Test transaction not rolling back - spring

Using the spring testing framework, my transactions do not roll back and I have absolutely no idea why. I've spent a good few days trying to find answers on SO but to no avail so I decided to post.
Testfile
#RunWith(SpringJUnit4ClassRunner.class)
#ContextConfiguration("/applicationContextTest.xml")
#Transactional
public class joinTest {
#Autowired
private DAO AccountDAO;//My DAO is annotated with #Repository
#Before
public void beforeMethod()
{
//log4j append code
}
#Test
public void saveMethod()
{
Account acct = new Account();
acct.setUsername("USER");
SmokeEvent evt = new SmokeEvent();
evt.setDateSmoked(new DateTime());
evt.setAccount(acct);
AccountDAO.addSmokeEvent(evt);
}
}
applicationContext.xml
<context:component-scan base-package="com.abstinence.Logic"/>
<context:annotation-config/>
<bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<property name="driverClassName" value="org.hsqldb.jdbcDriver"/>
<property name="url" value="jdbc:hsqldb:hsql://82.165.173.127/testdb"/>
<property name="username" value="SA"/>
<property name="password" value=""/>
</bean>
<bean id="sessionFactory" class="org.springframework.orm.hibernate4.LocalSessionFactoryBean">
<property name="dataSource" ref="dataSource"/>
<property name="packagesToScan" value="com.abstinence.Logic"/>
<property name="hibernateProperties">
<props>
<prop key ="dialect">org.hibernate.dialect.HSQLDialect</prop>
<prop key="javax.persistence.validation.mode">none</prop>
</props>
</property>
</bean>
<tx:advice id="txAdvice">
<tx:attributes>
<tx:method name="*"/>
</tx:attributes>
</tx:advice>
<aop:config>
<aop:pointcut id="hibernateDAOOperation" expression="execution(* com.abstinence.Logic.AccountDAO.*(..))"/>
<aop:advisor advice-ref="txAdvice" pointcut-ref="hibernateDAOOperation"/>
</aop:config>
<bean id="transactionManager" class="org.springframework.orm.hibernate4.HibernateTransactionManager">
<property name="sessionFactory" ref="sessionFactory" />
</bean>
I have checked the logs from log4j. The unusual thing is there is no mention of a rollback anywhere. There is a mention of the logs creating a session and inserting the data into the database but nothing about a rollback.
Someone please help me

Adding the following annotation to your test class #TransactionConfiguration(defaultRollback = true) should fix your issue.

You mention that the AccountDAO is annotated with the #Repository annotation. Have you also annotated the DAO with #Transactional? Without it, no transaction will be created when the addSmokeEvent() method is executed in the test. Consequently, the event will be added to your DAO, but the transaction manager cannot rollback the operation.

Related

Embedded H2 Database for Spring unit test with Liquibase: No data in tables when running test

I have embedded H2 database for my Spring unit tests. The tables and data should be initialized with Liquibase. However, when a test is running, there are no data in the table.
I'm using Spring 4.2.1, Liquibase 4.7.1 and H2 2.1.210.
Below is my implementation:
The datasource is declare in .xml file
<bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<property name="driverClassName" value="org.h2.Driver" />
<property name="url" value="jdbc:h2:mem:test;MODE=Oracle;DB_CLOSE_DELAY=-1;DB_CLOSE_ON_EXIT=FALSE" />
<property name="username" value="test" />
<property name="password" value="test" />
</bean>
<bean id="liquibase" class="liquibase.integration.spring.SpringLiquibase">
<property name="dataSource" ref="dataSource" />
<property name="changeLog" value="classpath:liquibase/changelog/sil_client_init.h2.sql" />
<property name="contexts" value="test" />
</bean>
<!-- Session factory -->
<bean id="sessionFactory"
class="org.springframework.orm.hibernate4.LocalSessionFactoryBean">
<property name="dataSource" ref="dataSource" />
<property name="configLocation" value="classpath:hibernate-config.xml" />
</bean>
<!-- Transaction manager -->
<bean id="txManager"
class="org.springframework.orm.hibernate4.HibernateTransactionManager">
<property name="sessionFactory" ref="sessionFactory"/>
</bean>
The sil_client_init.h2.sql file contains SQL contains changeset for creating and inserting several data in the table.
I have a super class which load the context, including the "liquibase" bean declared above.
#RunWith(SpringJUnit4ClassRunner.class)
#ContextConfiguration(locations = { "classpath*:applicationContext.xml" })
#Ignore
public class SpringApplicationContextIT {
#Before
public void setUp() {
BasicConfigurator.configure();
FacesContextMocker.mockFacesContext();
assertNotNull(applicationContext);
}
#Autowired
private ApplicationContext applicationContext;
}
From which my test class inherits
public class ClientDAOTest extends SpringApplicationContextIT {
#Autowired
private IClientDAO simpleClientDAO;
#Test
#Transactional
public void getAllClients() throws ClientDAOException {
simpleClientDAO.find();
}
When running getAllClients(), the context are loaded and there is log showing that my changesets Liquibase were running. However, when the test arrives at simpleClientDAO.find(), my Client table is empty.
Any idea of how to fix, how this could happen or how I could investigate the reason would be appreciated. Thank you so much in advance!
For those who might have the same problem, turn out the datasource is properly loaded but my sessions are not correctly connected.
I had to specify a package to scan for my sessionFactory bean:
<bean id="sessionFactory"
class="org.springframework.orm.hibernate4.LocalSessionFactoryBean">
<property name="dataSource" ref="dataSource" />
<property name="packagesToScan">
<value>com.myApp.dao.entity</value>
</property>
<property name="configLocation" value="/WEB-INF/classes/hibernate-config.xml" />
</bean>

Why does AOP managed transactions not work in my unit tests?

I've configured Spring solely based on XML. Transactions are managed by Hibernate, and I'm using AOP to manage transaction boundaries.
However, when running unit tests, why is it that my AOP configuration not kicks in? I need to add annotations such as #Transactional to the test method to make sure that database operations gets wrapped in transactions, even though I've configured AOP to wrap calls to service methods in transactions.
Why doesn't my AOP configuration apply to tests also?
applicationcontext.xml
<aop:aspectj-autoproxy/>
<!-- Data Source -->
<bean id="companyDomainDataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource" destroy-method="close">
<property name="driverClass" value="${jdbc.driverClassName}" />
<property name="jdbcUrl" value="${jdbc.master.url}" />
<property name="user" value="${jdbc.master.username}" />
<property name="password" value="${jdbc.master.password}" />
<property name="acquireIncrement" value="1" />
<property name="minPoolSize" value="2" />
<property name="maxPoolSize" value="20" />
<property name="maxIdleTime" value="4" />
</bean>
<!-- Session Factory -->
<bean id="companyDomainSessionFactory" class="org.springframework.orm.hibernate3.LocalSessionFactoryBean">
<property name="dataSource" ref="companyDomainDataSource"/>
<property name="mappingResources">
<list>
<value>/com/company/pas/entity/mapping/partner.hbm.xml</value>
</list>
</property>
</bean>
<!-- Transaction Manager -->
<bean id="companyDomainTransactionManager" class="org.springframework.orm.hibernate3.HibernateTransactionManager">
<property name="sessionFactory" ref="companyDomainSessionFactory"/>
</bean>
<!-- Transaction Advice -->
<tx:advice id="companyDomainTransactionAdvise" transaction-manager="companyDomainTransactionManager">
<tx:attributes>
<!--<tx:method name="get*" propagation="SUPPORTS" read-only="true"/>-->
<tx:method name="*" propagation="REQUIRED"/>
</tx:attributes>
</tx:advice>
<aop:config>
<aop:pointcut id="serviceMethods" expression="within(com.company.pas.dao.*)"/>
<aop:advisor advice-ref="companyDomainTransactionAdvise" pointcut-ref="serviceMethods"/>
</aop:config>
unit test
#RunWith(SpringJUnit4ClassRunner.class)
#ContextConfiguration(locations = {"/applicationContext.xml"})
#TransactionConfiguration(transactionManager="companyDomainTransactionManager", defaultRollback=true)
public class PartnerCreateTest extends AbstractActionTest {
#Autowired #Qualifier("createPartnerAction") AbstractAction action;
#Test
#Transactional
public void testExecute() throws Exception {
// Create partner.
Representation rep = mock(Representation.class);
Request req = mock(Request.class);
Response resp = mock(Response.class);
when(rep.getText()).thenReturn(getContentsOf("com/company/pas/entity/xml/partner-create.xml"));
when(req.getEntity()).thenReturn(rep);
AbstractRequestModel crm = action.getRequestModelParser().parse(req, resp);
action.execute(crm);
}
}
When you add #Transactional to a test method you get a rollback by default. When you don't you should expect transactions to commit (they don't know they are in a test).

Spring transactions doesn't work with Oracle Express

I have a simple standalone application to test transaction management with Spring.
Have Oracle Express Edition.
Run the following to enable XA
grant select on sys.dba_pending_transactions to user_test;
grant select on sys.pending_trans$ to user_test;
grant select on sys.dba_2pc_pending to user_test;
grant execute on sys.dbms_system to user_test;
My Java code is pretty much as follow:
public class DbUpdater
{
private static final ApplicationContext context =
new ClassPathXmlApplicationContext(new String[] {"spring_transactions.xml"});
private static Logger log = LoggerFactory.getLogger(DbUpdater.class);
#Transactional(propagation=Propagation.REQUIRED, readOnly=false)
public void updateData() {
IMasterDAO ds1 = context.getBean("masterDao", IMasterDAO.class);
log.info("Insert using ds1");
ds1.insert("insert into users values(?,?)", "user1", "John Hamilton");
log.info("Insert using ds1 finished successfully");
throw new RuntimeException("A runtime exception");
}
}
So all the idea is too see transaction rolling back.
I run with several configuration examples and record is committed all the time.
No rollback is performed. No errors nothing, only expected
Exception in thread "main" java.lang.RuntimeException: A runtime exception
at com.test.spring.transation.DbUpdater.updateData(DbUpdater.java:22)
My last config is this:
<bean id="txManager"
class="org.springframework.transaction.jta.JtaTransactionManager">
<property name="transactionManager" ref="bitronixTransactionManager" />
<property name="userTransaction" ref="bitronixTransactionManager" />
</bean>
<bean id="btmConfig" factory-method="getConfiguration"
class="bitronix.tm.TransactionManagerServices">
<property name="serverId" value="spring-btm" />
</bean>
<bean id="bitronixTransactionManager" factory-method="getTransactionManager"
class="bitronix.tm.TransactionManagerServices"
depends-on="btmConfig,dataSource"
destroy-method="shutdown" />
<bean id="dataSource" class="bitronix.tm.resource.jdbc.PoolingDataSource"
init-method="init" destroy-method="close">
<property name="className" value="oracle.jdbc.xa.client.OracleXADataSource"/>
<property name="uniqueName" value="myOracleDataSource"/>
<property name="minPoolSize" value="0"/>
<property name="maxPoolSize" value="5"/>
<property name="allowLocalTransactions" value="true"/>
<property name="testQuery" value="select sysdate from dual"/>
<property name="driverProperties">
<props>
<prop key="user">${jdbc.username}</prop>
<prop key="password">${jdbc.password}</prop>
<prop key="URL">${jdbc.url}</prop>
</props>
</property>
</bean>
<bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
<property name="dataSource" ref="dataSource"></property>
</bean>
<bean id="masterDao" class="com.test.spring.transation.MasterDAO">
<property name="jdbcTemplate" ref="jdbcTemplate"></property>
</bean>
</beans>
The JDBC template being instantiated via supplied data source, seems to work with its own transaction [there by the automatic begin and commit transaction]. The exception is thrown after that which operates in seperate commit/rollback cycle and hence you see that the writes persisted. To verify it, you can move the code to throw exception in MasterDAO class and examine rollback.

how to invoke multiple http webservice in mule flow in transaction?

I am new to mule.
I have a spring-hibernate mule setup. Suppose there are 3 webservice.Aim is to invoke all those webservice in a mule flow so that all 3 will be in a transaction. so that suppose if 3rd webservice fails then the previous 2 will be rolled back automatically.
Here is my code snippet what I tried.
my mule-flow.xml(currently I have only one webservice,kindly let me know how can I add multipe webservice call in flow?)
<spring:beans>
<spring:import resource="classpath:spring-mule.xml"/>
<spring:import resource="classpath:applicationContext-persistence.xml"/>
</spring:beans>
<flow name="addCustomer" doc:name="addCustomer">
<http:inbound-endpoint exchange-pattern="request-response"
address="http://localhost:8081/pos/addCustomer" doc:name="HTTP" />
<cxf:simple-service serviceClass="com.proj.pos.webservice.interfac.CustomerService" doc:name="SOAP"/>
<component ><spring-object bean="customerService"/></component>
</flow>
</mule>
My spring-mule.xml
<bean id="customerService" class="com.proj.pos.webservice.implementation.CustomerServiceImpl">
<property name="cusDao" >
<ref local="customerDao"/>
</property>
</bean>
My:applicationContext-persistence.xml
<bean id="datasource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<property name="driverClassName" value="oracle.jdbc.OracleDriver" />
<property name="url" value="jdbc:oracle:thin:#localhost:1521:xe" />
<property name="username" value="xyz" />
<property name="password" value="xyz" />
</bean>
<bean id="sessionFactory"
class="org.springframework.orm.hibernate3.LocalSessionFactoryBean">
<property name="dataSource" ref="datasource" />
<property name="configLocation">
<value>classpath:hibernate.cfg.xml</value>
</property>
<property name="configurationClass">
<value>org.hibernate.cfg.AnnotationConfiguration</value>
</property>
<property name="hibernateProperties">
<props>
<prop key="hibernate.dialect">org.hibernate.dialect.Oracle10gDialect</prop>
<prop key="hibernate.show_sql">true</prop>
<prop key="cache.provider_class">org.hibernate.cache.NoCacheProvider</prop>
<prop key="hibernate.connection.release_mode">auto</prop>
</props>
</property>
</bean>
<tx:annotation-driven />
<bean id="transactionManager"
class="org.springframework.orm.hibernate3.HibernateTransactionManager">
<property name="sessionFactory" ref="sessionFactory" />
</bean>
<bean id="customerDao" class="com.proj.pos.dao.implementation.CustomerDaoImpl">
<property name="sessionFactory">
<ref local="sessionFactory"/>
</property>
</bean>
my CustomerServiceImpl
#WebService(endpointInterface = "com.proj.pos.webservice.interfac.CustomerService",
serviceName = "CustomerService")
public class CustomerServiceImpl implements CustomerService {
#Autowired
private CustomerDao cusDao;
#Transactional //NOTE:USING THIS ANNOTATION I AM ABLE TO ACHIEVE THE BELOW METHOD //IN TRANSACTION,BUT I BELEIVE THIS FEATURE WILL NOT WORK IF WE HAVE MULTIPLE WEBSERVICE CALL
#Override
public Customer addCustomer(CustomerDto dto) {
Customer customer=new Customer(dto.getCustomerId(), dto.getFname(), dto.getLname(), dto.getAge(), dto.getDateOfBirth(), dto.getAddress());
customer.setCustomerId(cusDao.persist(customer));
return customer;
}
public CustomerDao getCusDao() {
return cusDao;
}
public void setCusDao(CustomerDao cusDao) {
this.cusDao = cusDao;
}
}
Please let me know any solution.Thanks
By seeing your question what I understood is your trying to make 3 web-service calls and you want to make all three calls in a single transaction.
As you are making a call to another system (Web-service in your case) you don't have control to maintain the transaction.
In your case you can use a Scatter gather router to call three web-services if any route(web-service call) is failed it will throw CompositeRoutingException, you can very well catch this exception in your catch exception strategy.
In your catch exception strategy you need to do the roll back activities (make another web-service call or db call which will fulfill your rollback requirement ).
As per my understanding, you have a three or more webservices calls and some db operations. you want to rollback if any service call fails.
Write a spring bean as below for SpringTransactionFactory and set transationManager property (ref from your applicationContext-persistence.xml)
<spring:beans>
<spring:import resource="classpath:spring-mule.xml"/>
<spring:import resource="classpath:applicationContext-persistence.xml"/>
<spring:bean id = "transactionFactory" class = "org.mule.module.spring.transaction.SpringTransactionFactory">
<spring:property ref="transactionManager" name=""></spring:property>
</spring:bean>
</spring:beans>
And add a tansactionfactory ref to inboundEndpoint as below
<http:inbound-endpoint exchange-pattern="request-response"
address="http://localhost:8081/pos/addCustomer" doc:name="HTTP" >
<custom-transaction action="ALWAYS_BEGIN" factory-ref="transactionFactory"/>
</http:inbound-endpoint>
Complete flow will be in single transaction and inclouding dao classes

In spring, what code is used to inject the value for the #PersistenceContext annotated variables?

Using a ClassPathXmlApplicationContext object I want to get the same EntityManager that is being used by other parts of the app which get it injected via:
#PersistenceContext(unitName="accessControlDb") private EntityManager em;
Using ctx.getBean("access-emf") I can get the EntityManagerFactory which is defined in the applicationContext.xml. Using that I can create a new EntityManager, but I can't get the existing EntityManager used by the rest of the app.
I just can't figure out what code is executed to inject the value for the #PersistenceContext annotation.
<bean id="jotm" class="org.springframework.transaction.jta.JotmFactoryBean"/>
<bean id="innerNgsdpDataSource" class="org.enhydra.jdbc.standard.StandardXADataSource">
<property name="driverName" value="${ngsdp.jdbc.driver}"/>
<property name="url" value="${ngsdp.jdbc.url}"/>
<property name="user" value="${ngsdp.jdbc.username}"/>
<property name="password" value="${ngsdp.jdbc.password}"/>
<property name="transactionManager" ref="jotm"/>
</bean>
<bean id="ngsdpDataSource" class="org.enhydra.jdbc.pool.StandardXAPoolDataSource">
<property name="transactionManager" ref="jotm"/>
<property name="dataSource" ref="innerNgsdpDataSource"/>
<property name="user" value="${ngsdp.jdbc.username}"/>
<property name="password" value="${ngsdp.jdbc.password}"/>
<property name="maxSize" value="4"/>
<property name="checkLevelObject" value="2"/>
<property name="jdbcTestStmt" value="select 1 from dual"/>
</bean>
<bean id="myEmf" name="moservices" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
<property name="dataSource" ref="ngsdpDataSource"/>
<property name="persistenceXmlLocation" value="WEB-INF/moservices-persistence.xml" />
<property name="jpaVendorAdapter" ref="hibernate_jpa_vendor_adapter" />
<property name="jpaPropertyMap" ref="jpa_property_map"/>
<property name="jpaDialect" ref="hibernate_jpa_dialect"/>
</bean>
If using spring-managed transactions, you can get the current EntityManager by calling
EntityManagerFactory emFactory = ctx.getBean("access-emf");
EntityManagerHolder emHolder =
(EntityManagerHolder) TransactionSynchronizationManager.getResource(emFactory);
EntityManager em = emHolder.getEntityManager();
This is most often the current EntityManager. But this is something which should be avoided (except possibly in unit-tests), as stated in the spring docs:
To be used by resource management code but not by typical application code
Another approach might be to intercept your service calls using Spring AOP, inject the #PersistenceContext in the advice, and set in in a ThreadLocal of yours. Later, you can get it from that ThreadLocal.

Resources