I'm using java 1.6 and spring 3.0.4, I want to realize a java functionality that
calculate new data values
update one-by-one the existing values on the database
If in any of this step there's an error I want to rollback the whole transaction and come back to the previous state.
I already realized all this pieces of code, I just want to put them together. How I can manage this with the existing spring values that are working with #Entity and #Column annotations?
Thanks!
Short answer: as you're using Spring, the easiest would be to use the transaction management, creating a service that represents this transaction unit and annotate the method with #Transactional
In practice, you need to configure a PlatformTransactionManager in your application. As you seem to use JPA, the JpaTransationManager seems like an obvious choice. To enable the processing of the #Transactional annotation, you can either use #EnableTransactionManagement or the <tx:annotation-driven/> namespace. Both are explained in the Javadoc of #EnableTransactionManagement
By default, a runtime exception thrown from that annotated method will manage a transaction rollback. If your code is using checked exceptions, you'll have to configure the rollbackFor attribute of the annotation.
There are more details and examples available in the documentation
For people that need the same configuration, here you can find how I solved this problem, integrating Hibernate with Spring.
<!-- session factory activate the transaction modules for the specified classes -->
<bean id="sessionFactory" class="org.springframework.orm.hibernate3.annotation.AnnotationSessionFactoryBean">
<property name="dataSource">
<ref bean="dataSource" />
</property>
<property name="configLocation" value="classpath:config-hibernate.xml" />
<property name="packagesToScan">
<list>
<!-- Additional packages required to be added if entities located elsewhere -->
<value>com.some.package.dao</value>
<value>com.some.package.model</value>
<value>com.some.package.SpecificClass</value>
</list>
</property>
<property name="mappingResources" ref="mappingResources"/>
<bean id="mappingResources" class="org.springframework.beans.factory.config.ListFactoryBean">
<property name="sourceList">
<list>
<!-- here you can add your hibernate mapping query that you want to use on transaction -->
<value>config-hibernate-mapping.xml</value>
</list>
</property>
</bean>
<!-- This will activate transactional annotation -->
<tx:annotation-driven transaction-manager="transactionManager" />
#Service
#Transactional
public class SpecificClass {
// write your method, everyone of them will be transactional
// and there will be a commit in case of success or rollback in case of exception
}
Related
Premise
I have a Spring 5.1.5 project with Hibernate 5.4.1
The compilation goes through fine but while running test cases for a particular package I see multiple tests failing. All with the same error:
javax.persistence.TransactionRequiredException: no transaction is in progress at com.project.server.package.dao.impl.SomeDAOImplTest.someTest(SomeDAOImplTest.java:54)
The Problem
Now I know that Hibernate 5 enforces the check for a transaction and it doesn't find one here and throws an exception. My question is why does it do that given I have transactions initialized via spring context.
My test case:
#ContextConfiguration({ "classpath:/spring/applicationContext-package-dao--test.xml" })
public class SomeDAOImplTest extends AbstractDAOTest {
#Autowired
private SomeDAO someDAO;
private className obj;
#Before
public void setUp() {
obj = new ClassName();
obj.setId(3);
someDAO.saveOrUpdate(obj);
}
My applicationContext-package-dao--test.xml:
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
<import resource="classpath:/spring/applicationContext-persistence-datasource-test.xml" />
<import resource="classpath:/spring/applicationContext-package-dao.xml" />
</beans>
The imported context applicationContext-persistence-datasource-test.xml has a bean txProxyTemplate as below:
<beans>
.
.//other beans
.
<bean id="txProxyTemplate" abstract="true" class="org.springframework.transaction.interceptor.TransactionProxyFactoryBean">
<property name="transactionManager" ref="transactionManager" />
</bean>
<bean id="transactionManager" class="com.desktone.transaction.DtResourcelessTransactionManager" />
<tx:annotation-driven transaction-manager="transactionManager" proxy-target-class="true" />
.
.//other beans
.
</beans>
The other applicationContext-package-dao.xml has the bean definition for SomeDAO which has txProxyTemplate as it's parent.
<bean id="SomeDAO" parent="txProxyTemplate">
<property name="target">
<bean class="com.project.server.package.dao.impl.SomeDAOImpl">
<property name="sessionFactory" ref="sessionFactory" />
</bean>
</property>
<property name="transactionAttributes">
<props>
<prop key="saveOrUpdate">PROPAGATION_REQUIRED</prop>
<prop key="delete">PROPAGATION_REQUIRED</prop>
<prop key="*">PROPAGATION_SUPPORTS,readOnly</prop>
</props>
</property>
</bean>
The saveorupdate call from SomeDAOImplTest calls SomeDAOImpl whose spring context config is applicationContext-package-dao.xml and has the Hibernate saveorupdate() call.
Things I have Tried:
Manually adding #Transactional tag to SomeDAOImplTest. (still throws no tx error)
Experimenting with PROPAGATION.REQUIRES_NEW (still throws no tx error) & PROPAGATION.MANDATORY(says marked mandatory but no tx).
Made sure the autowire is initialzing the bean.
Primary Suspicion
I suspect somehow the someDAO bean is initialized but txProxyTemplate bean isn't, so no transactionManager is in place. However, I have found no clues to coroborate this.
For me, this was happening because of a very fundamental issue. I'll explain the issue and the fix will be intuitive to everyone afterward.
When a Spring application runs all the beans are loaded in a single/global context. So even if some spring bean configuration depends on a transaction bean(for me it was txProxyTemplate) which isn't present in the same package at runtime it will be able to access it.
However, that's not true for a test case. My tests were reporting no transaction in progress since they couldn't load the txProxyTemplate and actually start a transaction. So my tests never ran in a transaction and I didn't know any better until I upgraded to Hibernate 5 and they put a hard constraint on this.
As you might have guessed defining the txProxyTemplate in the same spring config helped me work past this issue.
Good learning.
I am able to inject EntityManager in my Service class without defining any persistence-unit.
This is my configuration:
<bean id="transactionManager" class="org.springframework.orm.jpa.JpaTransactionManager">
<property name="entityManagerFactory" ref="entityManagerFactory" />
</bean>
<bean id="entityManagerFactory" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
<property name="dataSource" ref="dataSource" />
</bean>
<jpa:repositories base-package="com.example"></jpa:repositories>
In my Service class:
#PersistenceContext
private EntityManager entityManager;
// THIS WORKS!
final Session session = entityManager.unwrap(Session.class);
Is it because of the jpa:repositories ?
Spring ORM package's LocalContainerEntityManagerFactoryBean class makes this possible. It uses DefaultPersistenceUnitManager class to build an instance of PersistenceUnitInfo which can then be provided to PersistenceProvider class's createContainerEntityManagerFactory. Hibernate implements this interface so that Spring can create an instance of EntityMangerFactory class.
DefaultPersistenceUnitManager class is the one that creates a persistenceUnit called default and finds all the entity classes going through the classes on the classpath. Same information acquired from the persistence.xml has been taken in with a alternative approach like this without having a physical persistence.xml file.
Finally Spring uses JpaVendorAdapter configured to get the JPA provider- specific EntityManagerFactory instance.
Spring data JPA specific <jpa:repositories base-package="...." /> or #EnableJpaRepositories uses to scan all the beans annotated with #Repository to provide dynamic queries and other features. This is not an exhaustive explanation but you see how this "magic" happens.
You can find more on grepcode or download the sources to explore more.
I'm trying to use Oval 1.84 for getting around some validation constraints without boilerplates. The validation works when I mark fields with #NotNull (javax.validation.constraint and net.sf.oval.validator).
But doesn't work in the case of implementing constarints to method and constructor parameters.
Parameter validation requires the use of some method invocation intercepting bytecode. OVal provides ready to use implementations for AspectJ and Spring AOP.
With AspectJ
How to use it with AspectJ is documented in detail at http://oval.sourceforge.net/userguide.html#programming-by-contract
With Spring AOP
The usage with Spring AOP is outlined in the test case at
https://svn.code.sf.net/p/oval/code/trunk/src/test/java/net/sf/oval/test/integration/spring/SpringAOPAllianceTest.java
In Spring you need to configure your beans for which you want to have method parameter validation, e.g.:
<bean id="myService" class="com.example.MyService" />
And an Invocation Interceptor:
<bean id="ovalGuardInterceptor" class="net.sf.oval.guard.GuardInterceptor" />
<bean class="org.springframework.aop.framework.autoproxy.BeanNameAutoProxyCreator">
<property name="proxyTargetClass" value="false" />
<property name="interceptorNames">
<list>
<value>ovalGuardInterceptor</value>
</list>
</property>
<!-- the next line tells which beans you want to use validation for -->
<property name="beanNames" value="myService" />
</bean>
I am trying to use transactions with MyBatis and Spring and was wondering if there is a best practice on how to achieve this? Any hints or thoughts are appreciated.
My application wil be running in a tomcat container against a MySQL database.
You want to take a look at the #Transactional annotation docs
In terms of best practices it is a mixture of database transactions and spring. Look at where you need to roll back your data, do you need JTA, etc.
Example class
#Transactional
public class DefaultFooService implements FooService {
Foo getFoo(String fooName);
}
Example xml
<!-- this is the service object that we want to make transactional -->
<bean id="fooService" class="x.y.service.DefaultFooService"/>
<!-- enable the configuration of transactional behavior based on annotations --> <tx:annotation-driven transaction-manager="txManager"/>
<!-- a PlatformTransactionManager is still required -->
<bean id="txManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<!-- (this dependency is defined somewhere else) -->
<property name="dataSource" ref="dataSource"/>
</bean>
i'm facing a problem i really dunno how to catch the cat tail (if you hollow me the joke :o))
i have a webapp in war, deploy in tomcat. the war contains 4 Jars.
4 jars have 4 applicationContext, with 4 entityManager, and 4 TransactionManager.
declare like this (change the number 1..):
<bean id="entityManagerFactory1"
class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean"
p:dataSource-ref="dataSource1"
p:persistence-unit-name="com.xxxxxx.domain" >
<property name="jpaVendorAdapter">
<bean class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter"
p:databasePlatform="${ds1.dbdialect}" p:generate-ddl="false"
p:showSql="${ds1.showsql}" />
</property>
<property name="loadTimeWeaver">
<bean class="org.springframework.instrument.classloading.InstrumentationLoadTimeWeaver" />
</property>
</bean>
<bean id="transactionManager1" class="org.springframework.orm.jpa.JpaTransactionManager"
p:entityManagerFactory-ref="entityManagerFactory1">
depends-on="entityManagerFactory1" name="transactionManager1"/>
<tx:annotation-driven transaction-manager="transactionManager1" />
the context is load like this :
my problem i discover that when i'm using a BO of 3, the transaction is open with the datasource of 2.
moreover, if i do a persist i have the message :
AbstractSaveEventListener - delaying identity-insert due to no transaction in progress
BUT if i launch the jar 1 alone (for example), everything is working perfectly.
thanks a lot for your enlightement.
Let me guess:
in your servlet-context.xml, do you import the contexts? e.g.:
<import location="classpath:context1.xml" />
<import location="classpath:context2.xml" />
etc.
If you do, all bean definitions are copied from the imported context into the root context, which means that you have four different <tx:annotation-driven /> declarations, with different transaction managers. Probably the last one wins.
Possible solutions: Either use Qualifiers or use the XML style of transaction declaration.
What I'd do is probably to introduce a custom #Transactional annotation per context:
#Transactional("tx1")
#Inherited
#Retention(RetentionPolicy.RUNTIME)
#Target({ElementType.TYPE,ElementType.METHOD})
public #interface Transactional1 {}
Now annotate all methods in jar 1 with #Transactional1, in jar 2 with #Transactional2 etc. This mechanism is documented in the Section 10.5.6.3 Custom shortcut annotations