My name is Vasyl Khrystiuk‎ > ‎process‎ > ‎main‎ > ‎

transaction controll in spring

So, here will some notes about transaction controll in spring

Simple configuration for transaction support(via annotations):
<mvc:annotation-driven />
    <context:component-scan base-package="net.sinistersky.j2ee.spring_data_jpa" />
    	<jdbc:embedded-database id="dataSource" type="HSQL" />
	<bean id="entityManagerFactory" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
		<property name="dataSource" ref="dataSource" />
		<property name="jpaVendorAdapter">
			<bean class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter">
				<property name="generateDdl" value="true" />
				<property name="database" value="HSQL" />
			</bean>
		</property>
		<property name="persistenceUnitName" value="jpa.sample" />
	</bean>
	<bean id="transactionManager" class="org.springframework.orm.jpa.JpaTransactionManager">
		<property name="entityManagerFactory" ref="entityManagerFactory" />
	</bean>
    <tx:annotation-driven proxy-target-class="true"  transaction-manager="transactionManager"/>


Example repository:
package net.sinistersky.j2ee.spring_data_jpa.repo;

import java.util.List;

import javax.persistence.EntityManager;
import javax.persistence.EntityTransaction;
import javax.persistence.PersistenceContext;
import javax.persistence.PersistenceException;
import javax.persistence.TypedQuery;

import net.sinistersky.j2ee.spring_data_jpa.model.User;

import org.springframework.stereotype.Repository;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;


@Repository
@Transactional
public class UserRepository{
	
    @PersistenceContext
    private EntityManager em;
	
    @Transactional(rollbackFor=CostunNonRTE.class, propagation = Propagation.REQUIRES_NEW)
	public void save(User... user){
    	for (User us : user) {
            if (us.getId() == null) {
                em.persist(us);
    	    } else {
    	    	em.merge(us);
    	    }
		}
	}
	
	public User load(Long id){
		TypedQuery<User> query = em.createQuery("select a from User a where a.id = ?1", User.class);
		query.setParameter(1, id);
		return query.getSingleResult();
	}
	
	public List<User> loadAll(){
		TypedQuery<User> query = em.createQuery("select a from User a", User.class);
		return query.getResultList();
	}

	public void delete(Long id) {
		em.createQuery("DELETE FROM User u WHERE u.id=:id").setParameter("id", id).executeUpdate();
		em.flush();
	}
}

So, what actually happand here: 
Spring create new type of repository based on this one. There are two option for creating new type - dynamic proxy via JDK(in this case my repo shuld be declared in interface-way, or via CGLIB (in this case we shuld have CGLIB in classpath)). Switching between these two modea are in transaction config:
    <tx:annotation-driven proxy-target-class="true"  transaction-manager="transactionManager"/>
where true is point to CGLIB proxying.

Changed class wrap all methods in this way that any runtime exception is translated into javax.persistence.PersistenceException.
Also Transactional has these options:
propagation - define transaction strategy (more here: org.springframework.transaction.annotation.Propagation)
rollbackFor option allow to define costum nonRTE for rollback.
noRollbackFor option allow to define costum exception for no rollback.
All TRE by default is rollbacked. 
More interesting(if some is not working as expected): here, here, here, here
Comments