migrate hibernateTemplate to JPA 2 (executeWithNativeSession - doInHibernate) - spring

I am migrating my code from hibernate 3 (that is using hibernate template) to JPA 2. My project is using Spring as well.
Current project is using hibernatetempate as
hibernateTemplate.executeWithNativeSession(new HibernateCallback<Object>() {
#Override
public Object doInHibernate(Session session) throws SQLException {
Query query = session.getNamedQuery("updateToProcessed");
query.setParameter("Id", id);
return query.executeUpdate();
}
});
updateToProcessed is a simple update hql query. Please help to let me know how to convert it to JPA (to use entityManager)
I tried using
Query query = entityManager.createNamedQuery("updateToProcessed");
query.setParameter("Id", id);
query.executeUpdate();
Complete method is
#Override
public void updateAllBatchDetails(final String id) {
Query query = entityManager.createNamedQuery("updateToProcessed");
query.setParameter("Id", id);
query.executeUpdate();
}
But I am getting error as:
Caused by: javax.persistence.TransactionRequiredException: Executing an update/delete query
at org.hibernate.jpa.spi.AbstractQueryImpl.executeUpdate(AbstractQueryImpl.java:71)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at org.springframework.orm.jpa.SharedEntityManagerCreator$DeferredQueryInvocationHandler.invoke(SharedEntityManagerCreator.java:333)
at com.sun.proxy.$Proxy143.executeUpdate(Unknown Source)
I have configured transactionManager in applicationContext.xml like
I was expecting this answer and I have already configured that in applicationContext.xml but still I am getting that error
<tx:annotation-driven transaction-manager="transactionManager"/>
<bean id="transactionManager" class="org.springframework.orm.jpa.JpaTransactionManager"
p:entityManagerFactory-ref="entityManagerFactory"/>
But somehow #Transactional is working that I don't want to use.
This is the applicationContext.xml
<?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:p="http://www.springframework.org/schema/p"
xmlns:c="http://www.springframework.org/schema/c"
xmlns:tx="http://www.springframework.org/schema/tx" xmlns:aop="http://www.springframework.org/schema/aop"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util-2.0.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-3.0.xsd">
<context:component-scan base-package="com.batch"/>
<context:annotation-config/>
<context:spring-configured/>
<context:property-placeholder location="classpath:batch.properties"/>
<tx:annotation-driven transaction-manager="transactionManager"/>
<bean id="transactionManager" class="org.springframework.orm.jpa.JpaTransactionManager"
p:entityManagerFactory-ref="entityManagerFactory"/>
<aop:aspectj-autoproxy/>
<import resource="classpath:core/applicationContext.xml"/>
<import resource="classpath:spring/applicationContext-resources.xml"/>
<import resource="classpath:spring/applicationContext-batch.xml"/>
<bean id="entityManagerFactory"
class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean"
p:persistenceUnitName="default"
p:jpaVendorAdapter-ref="jpaVendorAdapter"
p:dataSource-ref="dataSource" />
<bean id="batchProperties" class="org.springframework.beans.factory.config.PropertiesFactoryBean"
p:location="classpath:batch.properties"/>
</beans>

To execute a bulk update you should do like below:
final String updateQuery = "update Person p SET p.name = 'Other Name'";
final int update = entityManager.createQuery(updateQuery).executeUpdate();
System.out.println("updated rows " + update);
Spring will handle the commit for you. [=
Edit: Caused by: javax.persistence.TransactionRequiredException
Have you configured the Transaction? To execute a update you must open a transaction.
With Spring you could use the annotation #Transactional in the method.

For this problem use a Tasklet where you execute your query.
Configure a step using a TaskletStep and you can set 'transaction manager' as well as 'transaction attributes' and errors should go away.

Related

rollback the data from first table if exception is thrown

I am using spring mvc and postgres as database
I have requirement to insert diff data into two tables with second table has one columns as foreignkey from first table
I am using jdbc template to connect with database
if some exception happens while inserting into second table i want to rollback the data from first table also
for this do i need use spring transactions concept? please suggest
I tried to implement transactions in this way
<?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:p="http://www.springframework.org/schema/p"
xmlns:security="http://www.springframework.org/schema/security"
xmlns:aop="http://www.springframework.org/schema/aop"
xmlns:tx="http://www.springframework.org/schema/tx"
xsi:schemaLocation="http://www.springframework.org/schema/security http://www.springframework.org/schema/security/spring-security-3.2.xsd
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.0.xsd
http://www.springframework.org/schema/tx
http://www.springframework.org/schema/tx/spring-tx-3.0.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop-3.0.xsd">
<!-- Define all the service beans that will be created in ePramaan -->
<context:annotation-config />
<tx:annotation-driven/>
<!-- END OF DAO beans Definitions -->
<bean class="org.springframework.jdbc.core.JdbcTemplate" p:dataSource-ref="dataSource" />
<!-- Create DataSource Bean -->
<bean id="dataSource" class="org.springframework.jndi.JndiObjectFactoryBean">
<property name="jndiName" value="java:comp/env/jdbc/ePramaanDB" />
</bean>
<bean id="jdbcSPProfileRepository"
class="in.cdac.epramaan.sp.dao.JdbcSPProfileRepository">
<property name="dataSource" ref="dataSource" />
</bean>
<bean id="transactionManager"
class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource" />
</bean>
JdbcSPProfileRepository is a class it contains method to insert data to database
I annotated class with #Transactional
But when i run the server it is throwing exceptions
14:44:01.223 [localhost-startStop-1] ERROR o.s.web.context.ContextLoader - Context initialization failed
org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'jdbcSPProfileRepository': Injection of autowired depende
ncies failed; nested exception is org.springframework.beans.factory.BeanCreationException: Could not autowire field: in.cdac.epramaan.common.bd.
MasterConfigBD in.cdac.epramaan.sp.dao.JdbcSPProfileRepository.masterConfigBD; nested exception is org.springframework.beans.factory.NoSuchBeanD
efinitionException: No qualifying bean of type [in.cdac.epramaan.common.bd.MasterConfigBD] found for dependency: expected at least 1 bean which
qualifies as autowire candidate for this dependency. Dependency annotations: {#org.springframework.beans.factory.annotation.Autowired(required=t
rue)}
#Component
#Transactional
public class JdbcSPProfileRepository implements SPProfileRepository {
private static final Logger logger = LoggerFactory
.getLogger(JdbcSPProfileRepository.class);
#Autowired
private JdbcTemplate jdbcTemplate;
/** The master config bd. */
#Autowired
MasterConfigBD masterConfigBD;
#Autowired
public JdbcSPProfileRepository(DataSource dataSource) {
}
#Override
#Transactional
public SPRegistrationResponse saveSPRegistrationDetails(
final SPRegistration spreg) {
SPRegistrationResponse spRegResponse = new SPRegistrationResponse();
Response response = null;
logger.debug("In saveSPRegistrationDetails : ");
try {/////}catch(){}
}
}
can anybody please suggest the solution
You have several options. One as you suggest is use Spring transactions.
http://simplespringtutorial.com/springDeclarativeTransactions.html
Or you can implemente your own ACID method where sharing the connection between transactions make it atomic. Look this example.
http://www.tutorialspoint.com/jdbc/commit-rollback.htm
The key is only commit on you connection("con") when you want finish your transaction. Then if something goes wrong before finish all your micro transactions, since you did not commit yet nothing will be persisted on your database.

Autowire JNDI Resource in Spring

I would like to know how to autowire JNDI resource in Spring controller using annotation.
Currently I can retrieve the resource using
<bean id="dataSource" class="org.springframework.jndi.JndiObjectFactoryBean">
<property name="jndiName" value="my/service"/>
</bean>
Is there any way, I can do the same thing using annotation? Something like
#Resource(name="my/service") ?
#Configuration
public class Configuration {
#Bean(destroyMethod = "close")
public DataSource dataSource() {
JndiDataSourceLookup dsLookup = new JndiDataSourceLookup();
dsLookup.setResourceRef(false);
DataSource dataSource = dsLookup.getDataSource("my/service");
return dataSource;
}
}
I use this configuration to inject a JNDI resource
spring config
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:beans="http://www.springframework.org/schema/beans"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:jee="http://www.springframework.org/schema/jee"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd
http://www.springframework.org/schema/jee
http://www.springframework.org/schema/jee/spring-jee.xsd">
<jee:jndi-lookup id="destination" jndi-name="java:/queue/inbound/jndiname" />
</beans>
Class
#Autowired
private javax.jms.Destination destination;

Why #Transactional doesn't work in my cord?

I am using Spring + mybatis in my project, and want to use #Transactional to start a transaction, so I add some configuration code in my dataSource.xml:
<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"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd
http://www.springframework.org/schema/tx
http://www.springframework.org/schema/tx/spring-tx-3.0.xsd"
default-lazy-init="true">
<tx:annotation-driven transaction-manager="oracletransactionManager"/>
<bean id="oracletransactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="oracledataSourceWrite"/>
</bean>
and this is part of my test code:
#Transactional
public void testTransaction() throws Exception {
// insert operation 1 without error
// insert operation 2 with exception ,on purpose, such as some data too long for column in mysql
}
After run the test, insert operation 1 insert into database successfully, and insert operation 2 fail, thus Transaction doesn't work any more, can anyone help me???
I test it in my main function.
Edit:
finally, I changed to another way with transaction by using TransactionProxyFactoryBean.
You have to define like this
#Transactional(rollbackFor=Exception.class)

JPA + Spring: UnexpectedRollbackException when Transaction is REQUIRED, REQUIRES_NEW or NESTED

I'm doing my first project with Spring, JPA, and GlassFish 3.1 and I'm having some troubles. I've been looking for a solution for a week, but I have found nothing.
I have an Entity (called Role), a GeneralReposiroty with general methods to access any entity, a RoleRepository which implements particular methods about Role, and a Service class, which calls RoleRepository. Methods of Service class are transactional, but I get RollBackException if the propagation property is REQUIRED, REQUIRES_NEW or NESTED. If propagation is MANDATORY, it's thrown an exception saying:
org.springframework.transaction.IllegalTransactionStateException: No existing transaction found for transaction marked with propagation 'mandatory'
at org.springframework.transaction.support.AbstractPlatformTransactionManager.getTransaction(AbstractPlatformTransactionManager.java:339)
at org.springframework.transaction.interceptor.TransactionAspectSupport.createTransactionIfNecessary(TransactionAspectSupport.java:262)
at org.springframework.transaction.interceptor.TransactionInterceptor.invoke(TransactionInterceptor.java:101)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:172)
at org.springframework.aop.framework.CglibAopProxy$DynamicAdvisedInterceptor.intercept(CglibAopProxy.java:631)
...
If it's NOT_SUPPORTED, NEVER or SUPPORT, select queries work fine, but I get the same RollbackException if I try to execute a create, update or delete query.
I've debugged the select queries, and before they throw the RollBackException, the query gets the result fine, and the exception is thrown just at the end of the function. In adition, if I get the Entities with find() of EntityManager and the service method doesn't have the #Transactional anotation, works fine, but if I make it transactional, it crashes with the same exception.
This happens with all entities I have, but I use that to explain the problem.
I think there is something wrong with my Spring configuration, but I don't know what.
This is the full trace of the exception (In some lines there are references to AuthenticationSuccessHandler class, because it's where I call to the service class from):
WARNING: StandardWrapperValve[default]: PWC1406: Servlet.service() for servlet default threw exception
org.springframework.transaction.UnexpectedRollbackException: JTA transaction unexpectedly rolled back (maybe due to a timeout); nested exception is javax.transaction.RollbackException: Transaction marked for rollback.
at org.springframework.transaction.jta.JtaTransactionManager.doCommit(JtaTransactionManager.java:845)
at org.springframework.transaction.support.AbstractPlatformTransactionManager.processCommit(AbstractPlatformTransactionManager.java:662)
at org.springframework.transaction.support.AbstractPlatformTransactionManager.commit(AbstractPlatformTransactionManager.java:632)
at org.springframework.transaction.interceptor.TransactionAspectSupport.commitTransactionAfterReturning(TransactionAspectSupport.java:314)
at org.springframework.transaction.interceptor.TransactionInterceptor.invoke(TransactionInterceptor.java:116)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:172)
at org.springframework.aop.framework.CglibAopProxy$DynamicAdvisedInterceptor.intercept(CglibAopProxy.java:631)
at com.citius.reservas.service.service$$EnhancerByCGLIB$$37b50d4.tryJPAFind(<generated>)
at com.citius.reservas.AuthenticationSuccessHandlerImpl.onAuthenticationSuccess(AuthenticationSuccessHandlerImpl.java:47)
...
Caused by: javax.transaction.RollbackException: Transaction marked for rollback.
at com.sun.enterprise.transaction.JavaEETransactionImpl.commit(JavaEETransactionImpl.java:428)
at com.sun.enterprise.transaction.JavaEETransactionManagerSimplified.commit(JavaEETransactionManagerSimplified.java:855)
at com.sun.enterprise.transaction.UserTransactionImpl.commit(UserTransactionImpl.java:208)
at org.springframework.transaction.jta.JtaTransactionManager.doCommit(JtaTransactionManager.java:842)
... 45 more
I have the following entity:
#Entity
#Table(name = "roles", catalog = "reservas")
#XmlRootElement
public class Role implements Serializable {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Integer id;
#NotNull
#Size(min = 1, max = 50)
private String name;
private static final long serialVersionUID = 1L;
GenericRepository, a general class, which is implemented by all the repositories:
public class GenericRepositoryImpl<T> implements GenericRepository<T> {
#PersistenceContext
private EntityManager em;
private Class<T> type;
public GenericRepositoryImpl( ){
Type t = getClass().getGenericSuperclass();
ParameterizedType pt = (ParameterizedType) t;
type = (Class) pt.getActualTypeArguments()[0];
}
#Override
public T find(Object pk) {
try{
return em.find(type, pk);
}catch(java.util.NoSuchElementException ex){
return null;
}
}
#Override
public T create(T t) {
em.persist(t);
em.flush();
em.refresh(t);
return t;
}
#Override
public List<T> query(Query q) {
List<T> list= q.getResultList();
if(list==null)
list=new ArrayList<T>();
return list;
}
}
This is the role repository:
#Repository
public class RoleRepositoryImpl extends GenericRepositoryImpl<Role>
implements RoleRepository{
#PersistenceContext
private EntityManager em;
#Override
public Role findByName(String name) {
Query q = (Query) this.em.createNamedQuery("Role.findByName");
q.setParameter("name", name);
Role r = (Role) q.getSingleResult();
return r;
}
#Override
public List<Role> findAll() {
Query q = (Query) this.em.createNamedQuery("Role.findAll");
return this.query(q);
}
}
The Service class:
#Service
public class service {
#Autowired
private RoleRepository roleRepository;
#Transactional
//This throws a RollBackException
public void tryJPAEmpty(){
roleRepository.findByName("example");
}
//This doesn't
public Role tryJPAFind(){
return roleRepository.find(new Integer(1));
}
}
Spring configuration (applicationContext.xml) is:
<?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:aop="http://www.springframework.org/schema/aop"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:jpa="http://www.springframework.org/schema/data/jpa"
xmlns:tx="http://www.springframework.org/schema/tx"
xmlns:jee="http://www.springframework.org/schema/jee"
xmlns:p="http://www.springframework.org/schema/p"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.2.xsd
http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-3.2.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.2.xsd
http://www.springframework.org/schema/data/jpa http://www.springframework.org/schema/data/jpa/spring-jpa-1.3.xsd
http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-3.2.xsd
http://www.springframework.org/schema/jee http://www.springframework.org/schema/jee/spring-jee.xsd
">
<context:component-scan base-package="com.***.***" />
<jpa:repositories base-package="com.***.***.repositories" />
<tx:annotation-driven />
<tx:annotation-driven transaction-manager="transactionManager" />
<context:annotation-config />
<beans>
<bean id="EntityManagerFactory" class="org.springframework.orm.jpa.LocalEntityManagerFactoryBean">
<property name="persistenceUnitName" value="JPAReservas"/>
</bean>
<bean class="org.springframework.dao.annotation.PersistenceExceptionTranslationPostProcessor"/>
<bean id="transactionManager"
class="org.springframework.transaction.jta.JtaTransactionManager" >
<property name="allowCustomIsolationLevels">
<value>true</value>
</property>
</bean>
</beans>
</beans>
Persistence.xml (I have a data source and a connection pool created in my GlassFish server):
<?xml version="1.0" encoding="UTF-8"?>
<persistence version="1.0" xmlns="http://java.sun.com/xml/ns/persistence"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/persistence
http://java.sun.com/xml/ns/persistence/persistence_1_0.xsd">
<persistence-unit name="JPAReservas" transaction-type="JTA">
<provider>org.eclipse.persistence.jpa.PersistenceProvider</provider>
<jta-data-source>Reservas_mysql</jta-data-source>
<!--Named queries-->
<mapping-file>META-INF/mapping/Role.xml</mapping-file>
<exclude-unlisted-classes>false</exclude-unlisted-classes>
</persistence-unit>
</persistence>
And finally, I have named queires in a xml file, like that:
SELECT r FROM Role r
<named-query name="Role.findByName">
<query>SELECT r FROM Role r WHERE r.name = :name</query>
</named-query>
I'm really noob with Spring and JPA, so if you know some improvements, or changes I can do, please tell me.
Ok, I've solved it changing transaction-type to RESOURCE_LOCAL, but at the beggining, Glassfish gives me a lot of troubles. That's the way I solved it:
I've add metadata-complete="true" to the header of web.xml. Here is explained why is this necesary:
<web-app xmlns="http://java.sun.com/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd"
version="3.0" metadata-complete="true">
I've changed my persistence.xml, because with RESOURCE_LOCAL the application won't use the connection pool of Glassfish, I have to put information about database connection:
<persistence-unit name="JPAReservas" transaction-type="RESOURCE_LOCAL">
<provider>org.eclipse.persistence.jpa.PersistenceProvider</provider>
<mapping-file>META-INF/mapping/User.xml</mapping-file>
<exclude-unlisted-classes>false</exclude-unlisted-classes>
<properties>
<property name="javax.persistence.jdbc.driver" value="com.mysql.jdbc.Driver"/>
<property name="javax.persistence.jdbc.url" value="jdbc:mysql://localhost:3306/reservas"/>
<property name="javax.persistence.jdbc.user" value="admin"/>
<property name="javax.persistence.jdbc.password" value="adminpassword"/>
</properties>
</persistence-unit>
And at the end, I've changed the applicationContext.xml (Spring configuration), because I can't use the same EntityManager class with RESOURCE_LOCAL as with JTA:
<bean id="transactionManager" class="org.springframework.orm.jpa.JpaTransactionManager">
<property name="entityManagerFactory" ref="EntityManagerFactory" />
</bean>
And that's all. I don't know why I can't use JTA like I was doing before, but I've solved it!!! :). Thank you!

Spring Transactions not rolling back

I have been using spring transactional management in a project dealing with JUnit Testing. I have gotten this to work fine for my JUnit tests but I cannot get it to work outside of that. Here is my basic scenario:
I have a class which handles DbUnit Initialization similar to this:
#TransactionConfiguration( defaultRollback = true )
#Transactional(propagation=Propagation.REQUIRED)
public class DbUnitManagerImpl implements DbUnitManager {
#Override
public void initializeDatabase(String location) {
// Does work to create a dataset from the file at location
// Calls a function within this class to execute the dbUnit initialization
runSetUp()
}
public void runSetUp() {
// Executes dbUnit call to initialize database
}
}
I am using this class in two different instances. I use it when running JUnit tests to initialize data and I also call these functions from a Backing Bean for a webpage.
The JUnit setup will properly rollback and looks like this:
#RunWith(SpringJUnit4ClassRunner.class)
#ContextConfiguration(locations = { "classpath:/context/applicationContext-rdCore.xml" })
#TransactionConfiguration( defaultRollback = true )
#Transactional(propagation=Propagation.REQUIRED)
public abstract class BaseDatabaseTest {
#Autowired private DbUnitManager dbUnitManager;
#Test
public void runTest1() {
dbUnitManager.initializeDatabase("D:\\test.xml");
}
}
My backing bean works in a similar way however it allows the DbUnitManagerImpl to do all the transactions. I have debugged that transactions are being started using:
System.out.println(TransactionSynchronizationManager.isActualTransactionActive());
In both cases true is displayed showing that a transaction is being started however rollback only occurs for the JUnit test. The backing bean looks like this:
#Service
#SessionScoped
public class DbUnitInitializerBean {
#Autowired private DbUnitManager manager;
/**
* Initializes the database using the files at <code>location</code>
*/
public void initializeDatabase() {
manager.initializeDatabase("D:\\test.xml);
}
}
A few notes:
The three classes mentioned above are obviously stripped down. They also reside in three different java projects. The backing bean resides in a web project which has the following application context:
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:cache="http://www.springframework.org/schema/cache"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:tx="http://www.springframework.org/schema/tx"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.1.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.1.xsd
http://www.springframework.org/schema/cache http://www.springframework.org/schema/cache/spring-cache.xsd
http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-3.1.xsd">
<context:annotation-config />
<cache:annotation-driven />
<context:component-scan base-package="com.nph.rd.dbunit" />
<import resource="classpath:/context/applicationContext-rdCore.xml"/>
</beans>
The application context for my test Project which houses the DbUnitManagerImpl class looks like:
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:cache="http://www.springframework.org/schema/cache"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:tx="http://www.springframework.org/schema/tx"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.1.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.1.xsd
http://www.springframework.org/schema/cache http://www.springframework.org/schema/cache/spring-cache.xsd
http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-3.1.xsd">
<context:annotation-config />
<cache:annotation-driven />
<import resource="classpath:/context/applicationContext-rdCore.xml"/>
</beans>
The main application context resides in the project which houses my JUnit tests and looks like:
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:cache="http://www.springframework.org/schema/cache"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:tx="http://www.springframework.org/schema/tx"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.1.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.1.xsd
http://www.springframework.org/schema/cache http://www.springframework.org/schema/cache/spring-cache.xsd
http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-3.1.xsd">
<context:annotation-config />
<tx:annotation-driven />
<context:component-scan base-package="com.nph.rd.dbunit" />
<context:component-scan base-package="com.nph.dbunit" />
<bean id="dbUnitManager" class="com.nph.dbunit.dao.impl.DbUnitManagerImpl">
</bean>
<!-- allows for ${} replacement in the spring xml configuration from the .properties file on the classpath -->
<context:property-placeholder location="classpath:/properties/core-system.properties" ignore-unresolvable="true"/>
<!-- Transaction Manager -->
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource" />
</bean>
<!-- OLTP data source -->
<bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
<property name="dataSource" ref="dataSource" />
</bean>
<bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<property name="driverClassName" value="${oltp.database.driverClassName}" />
<property name="url" value="${oltp.database.url}" />
<property name="username" value="${oltp.database.username}" />
<property name="password" value="${oltp.database.password}" />
</bean>
</beans>
The basic end goal is I will have my DbUnitManager class able to rollback on an exception basis when using it from the Backing Bean but have it rollback no matter what when used from my JUnit tests. Currently I have the DbUnitManager class set up to always rollback simply because I am trying to get transaction rollback to work in general. After I get it working I will move it over to rolling back on an exception basis.
Remove the following from your DbUnitManagerImpl
#TransactionConfiguration( defaultRollback = true )
This annotation only goes with the Spring TestRunner. By default the Spring TestRunner will rollback all transactions, so you can override that behavior with the #TransactionConfiguration.
If you are using a Spring TransactionManager (which you are), it will automatically rollback on uncaught runtime exceptions. If you want to rollback for checked exceptions, you can specify them in the #Transactional annotation or convert them to runtime ones.
#Transactional(rollbackFor = SomeCheckedException.class)
public void someMethod() {}

Resources