Why #Transactional doesn't work in my cord? - spring

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)

Related

migrate hibernateTemplate to JPA 2 (executeWithNativeSession - doInHibernate)

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.

Spring AOP Pointcut not called

i work with JSF 2.2 + Spring framework 3.2.4
So, i have this applicationContent.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"
xmlns:aop="http://www.springframework.org/schema/aop"
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/tx
http://www.springframework.org/schema/tx/spring-tx.xsd">
<aop:aspectj-autoproxy proxy-target-class="true" />
<tx:annotation-driven transaction-manager="transactionManager"/>
<context:annotation-config/>
<context:component-scan base-package="com.vulcan.controller" />
<context:component-scan base-package="com.vulcan.service" />
<context:component-scan base-package="com.vulcan.dao" />
<context:component-scan base-package="com.vulcan.spring.aop" />
.....
Then i have aspect component
in
package com.vulcan.spring.aop;
#Aspect
public class LoggingService {
private Log log = LogFactory.getLog(this.getClass());
#Pointcut("execution(* *.*(..))")
protected void loggingOperation() {}
#Before("loggingOperation()")
public void logJoinPoint()
{
System.out.println ("Hello");
}
....
With this type of execution i assume this pointcut will be triggered on every methods. But the problem is, this pointcut isn't triggered ? Any idea why ? Thanks
FYI, i using glassfish 4, and when i deploy my web app i didn't receive any error configuration. So i assume my configuration is fine.
#Aspect annotate classes aren't automatically detected by Spring and because it isn't detected it isn't known to the <aop:aspectj-autoproxy /> beans. So basically there is no aspect.
Either add #Component to your #Aspect annotated class(es) so that Spring can detect and use the aspect.
#Compopnent
#Aspect
public class LoggingService { ... }
or declare the aspect explictly in your xml file
<bean class="LoggingService" />
Either way the aspect will be picked up by the <aop:aspectj-autoproxy /> beans and the advice will be run.
Try using execution(* *(..)).

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() {}

Adding Xml configurations to a Spring ApplicationContext that is already setup

I was wondering if there is a way to do the following:
have my wep app startup with its servle-context.xml
When, at a certain point, one particular bean in this xml config is instantiated, it will add it's own xml configuration to the application context (or to a child perhaps?).
I'm asking this because I want to pack some functionality in a stand alone library and then reuse it in different projects, so that initializing a bean of this library will load its xml config.
What I wrote is:
public class IrisLibHelper {
ApplicationContext context;
ApplicationContext irisContext;
#Required
#Autowired
public void setContext(ApplicationContext ctx){
this.context = ctx;
ClassPathXmlApplicationContext xap = new ClassPathXmlApplicationContext(ctx);
xap.setConfigLocation("classpath:com/dariodario/irislib/xmldefs/irisconfig.xml");
this.irisContext = xap;
}
public ApplicationContext getIrisContext() {
return irisContext;
}
public void setIrisContext(ApplicationContext irisContext) {
this.irisContext = irisContext;
}
}
and the irisconfig.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:mvc="http://www.springframework.org/schema/mvc"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:aop="http://www.springframework.org/schema/aop" xmlns:tx="http://www.springframework.org/schema/tx"
xmlns:p="http://www.springframework.org/schema/p"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-2.5.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop-3.0.xsd
http://www.springframework.org/schema/tx
http://www.springframework.org/schema/tx/spring-tx-3.0.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-3.0.xsd
http://www.springframework.org/schema/mvc
http://www.springframework.org/schema/mvc/spring-mvc-3.0.xsd">
<!-- <context:component-scan base-package="com.dariodario"></context:component-scan> -->
<mvc:annotation-driven />
<bean
class="org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter"
p:synchronizeOnSession="true" />
<context:component-scan base-package="com.dariodario.iris.controllers"></context:component-scan>
</beans>
The problem is that it doesn't seem to scan the com.dariodario.iris.controllers package, in fact the controllers don't get mapped! (I've logging debugging on and I don't seen anything).
Why not use the tag <import resource="classpath:applicationConfig.xml" /> ? You can load a spring configuration file which is in jar. In a jar, the Spring XML configuration is always at the root. But if not, you can use this notation: <import resource="${configurablePath}/applicationConfig.xml" /> where configurablePath can be reach by a property place holder or other.
I think this way is cleaner than merging two Spring context.

loading multiple properties files from projects in workspace

I have three projects - proj-a, proj-b, and main such that main depends on proj-a and proj-b.
proj-a and proj-b each contains a module-context.xml and properties file.
proj-a module-context.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"
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-3.0.xsd">
<context:property-placeholder location="classpath:/META-INF/proj-a.properties"/>
<bean ... someProperty="${property-a}" />
</bean>
proj-a.properties
property-a=hello-a
proj-b's configuration is identical except a is replaced by b.
proj-b module-context.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"
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-3.0.xsd">
<context:property-placeholder location="classpath:/META-INF/proj-b.properties"/>
<bean ... someProperty="${property-b}" />
</bean>
proj-b.properties
property-b=hello-b
A Class in main wants to create an ApplicationContext that consists of both proj-a and proj-b's module-context.xml. The problem is that only one of the properties file is processed by spring. If proj-a's module-context.xml's loaded first, proj-b's properties file is never read.
The following snippet throws an Exception.
public static void main( String[] args ) throws IOException {
ApplicationContext context = new FileSystemXmlApplicationContext( new String[] {
"../proj-a/src/main/resources/META-INF/spring/module-context.xml",
"../proj-b/src/main/resources/META-INF/spring/module-context.xml"
} );
}
throws
Exception in thread "main" org.springframework.beans.factory.BeanDefinitionStoreException: Invalid bean definition with name '...' defined in file [...\proj-b\src\main\resources\META-INF\spring\module-context.xml]: Could not resolve placeholder 'property-b'
at org.springframework.beans.factory.config.PropertyPlaceholderConfigurer.processProperties(PropertyPlaceholderConfigurer.java:272)
at org.springframework.beans.factory.config.PropertyResourceConfigurer.postProcessBeanFactory(PropertyResourceConfigurer.java:75)
at org.springframework.context.support.AbstractApplicationContext.invokeBeanFactoryPostProcessors(AbstractApplicationContext.java:624)
at org.springframework.context.support.AbstractApplicationContext.invokeBeanFactoryPostProcessors(AbstractApplicationContext.java:599)
at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:398)
How can I properly load the properties files? Merging them is not a solution because properties are project specific.
I found a solution - set property ignoreUnresolvablePlaceholders to true.

Resources