views:

8389

answers:

2

How far does the spring framework go with transaction handling? My reading of the book "Spring In Action" suggestions with its examples that you create DAO methods that don't worry about Session and Transaction management fairly simply by setting up a session factory and transaction template in XML and then wiring them into your DAO. SpringSource.org's documentation, on the other hand, suggests that need tons of XML and/or annotation to make this happen.

What is the truth here, what is the simplest way I can take code along the lines of

get session from sessionfactory
open transaction
preform database actions
commit transaction with error handling

and make it just

preform database actions

reducing the amount of boiler plate transactional code that I have across my methods to a minimum?

+4  A: 

There is some work you are supposed to do to be able to do just that but it's not much at all. Supposedly, you will use JPA with pick your own provider, e.g. Hibernate. Then you need to place persistence.xml that defines the persistence unit in the META-INF folder:

<?xml version="1.0" encoding="UTF-8"?>
<persistence 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" 
             version="1.0">
    <persistence-unit name="YourDatabasePersistenceUnitName" transaction-type="RESOURCE_LOCAL"/>           
</persistence>

Next, define everything necessary for database connection in the Spring application context you use, at minimum it should contain these:

<bean id="propertyConfigurer"
     class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
     <property name="locations">
      <list>
       <value>/WEB-INF/jdbc.properties</value>  
     </property>
    </bean>

    <bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource" 
          destroy-method="close" scope="singleton">
     <property name="driverClassName" value="org.postgresql.Driver"/>
     <property name="url" value="${jdbc.url}"/>
     <property name="username" value="${jdbc.username}"/>
     <property name="password" value="${jdbc.password}"/>
    </bean>

    <bean id="entityManagerFactory" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
     <property name="persistenceUnitName" value="YourDatabasePersistenceUnitName"/>
     <property name="dataSource" ref="dataSource"/>
     <property name="jpaVendorAdapter">
      <bean class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter">
       <property name="database" value="POSTGRESQL" />
       <property name="databasePlatform" value="org.hibernate.dialect.PostgreSQLDialect"/>
       <property name="showSql" value="true"/>
             <property name="generateDdl" value="false"/>
      </bean>
     </property>  
    </bean>

    <bean id="transactionManager" class="org.springframework.orm.jpa.JpaTransactionManager">
        <property name="entityManagerFactory" ref="entityManagerFactory"/>
        <property name="dataSource" ref="dataSource"/>
    </bean>

<tx:annotation-driven transaction-manager="transactionManager" />

<bean class="org.springframework.orm.jpa.support.PersistenceAnnotationBeanPostProcessor" />

 <bean class="org.springframework.dao.annotation.PersistenceExceptionTranslationPostProcessor"/>

Some properties above may be changed or added depending on your needs. The example is for JPA with Hibernate and PostgreSQL database as you may have guessed.

Now you can simply define your data access methods like this:

@Repository
@Transactional
public class UserJpaDAO {

    protected EntityManager entityManager;

    @PersistenceContext
    public void setEntityManager(EntityManager entityManager) {
        this.entityManager = entityManager;
    }

    public void save(User theUser) {
        entityManager.persist(theUser);
    }

    public User update(User theUser) {
        return entityManager.merge(theUser);
    }
 }

where User is a JPA entity defined by your application. You may manager transactions at manager/controller layer that calls your DAOs - in fact I do it that way - but I placed it together here not to clutter example too much.

Nice references that you may want to go straight to instead of my examples is http://icoloma.blogspot.com/2006/11/jpa-and-spring-fucking-cooltm_26.html The top 3 links it references are worth going to as well.

grigory
Thanks for the answer, I'll play with this tomorrow at work. However, both of your links at the end are the same.
James McMahon
sorry, but the link I supplied contains 3 more links including the other one I had in mind...
grigory
Now the link appears to be down...
James McMahon
sorry, link should work now...
grigory
Is the XML order important?
James McMahon
The xml order should not be important besides obvious dependencies between beans.
grigory
+4  A: 

Spring provides at least 3 ways of transaction demarcation:

1) Programmatic handling, via TransactionTemplate or PlatformTransactionManager - light on config, but invasive

2) Declarative via XML - verbose XML, but non-invasive

3) Declarative via annotations - light on XML, not invasive

Which one you pick depends on which one best suits your needs, Spring doesn't make that choice for you. From your question, it sounds like the annotation approach is what you're after.

I suggest reading the Spring reference manual, the section of annotation-driven transaction handling. It's clear and concise.

I always consult the ref docs first, and only consult a book if it's not in the docs.

skaffman
Thanks for laying that out for me.
James McMahon