Spring JDBC & Transaction Support

General

Spring data access uses concept of templates to:

  • provide consistent error handling approach
  • provide consistent api

In the past, your DAOs previously extended base Spring DAO classes – this approach is no longer used/recommended (Spring 3.x +) –  use plain annotated POJOs with @Repository annotation.

New Terminology:

  • Repository == DAO

Recommendations

  • one template instance per Repository – Template code is threadsafe, but shared usage (between DAOs/Repositories) would result in blocking calls and reduced performance
  • instead create Template from a Factory, or better still, configure with scope=”prototype”

Exception Handling (in Spring’s View)

  • Checked Exceptions – force developers to add additional code to handle exceptions, bad from the point of view of tight coupling
  • Unchecked Exceptions – can be passed up hierarchy to suitable place to handle, without unnecessary throws clauses
  • Spring framework always uses Unchecked/Runtime Exceptions

Spring Data Access Base Exception

  • DataAccessException -manly subtypes, for example, DataIntegrityViolationException

JDBC Namespace for xml Config

  • provides shortcut config for creating/defining jdbc data access
  • useful for development and testing, provides embedded database support (eg H2)
  • <jdbc:embedded-database…>
  • <jdbc:initialize-database …> – allows running f sql setup scripts

Verbocity of JDBC api approach together with Checked exceptions is simplified by using JDBCTemplate to handle the plumbing, allow using to focus on just what is important, eg the SQL itself and executing code

JDBC Repositories

  • Implement your business interface
  • Annotate with @Repository
  • Inject DataSource in Repository constructor
  • Constructor creates new JdbcTemplate instance from passed DataSource
@Transactional
@Repository
public class ExampleRespositoryImpl implements ExampleRepository
{
    private JdbcTemplate jdbcTemplate;

    public ExampleRespositoryImpl(DataSource datasource)
    {
        this.jdbcTemplate(new JndiTemplate(datasource));
    }
}

Config shortcuts

    • lookup Datasource using:
<jee:jndi-lookup id="datasource" jndi-name="java:/comp/env/jdbc/name"/>

JdbcTemplate.queryForMap()

  • returns single row with columns as keys in the map

JdbcTemplate.queryForList()

  • returns List of Maps (as above)

Spring Container Transaction Support

Configure PlatformTransactionManger according to container and/or persistence technology being used:

e.g:

<bean id="txManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
  <property name="dataSource" ref="dataSource"/>
</bean>
<jee:jndi-lookup id="dataSource" jndi-name="jdbc/jpetstore"/> 

<bean id="txManager" class="org.springframework.transaction.jta.JtaTransactionManager" />

Other PlatformTransactionMangerImplementations (see here for full list):

  • JtaTransactionManager – if using container provided JTA implementation
  • WebLogicJtaTransactionManager – use Weblogic’s transaction manager
  • JpaTransactionManager – use with JPA
  • HibernateTransactionManager – use with Hibernate

Enable Annotation based transaction declarations:

<tx:annotation-driven/>

@Transactional annotation can be at class level or individual method level

AOP based transactional configuration

Add transaction behavior by matching beans/methods transactional based on patterns: (example config from Spring manual : http://static.springsource.org/spring/docs/3.1.2.RELEASE/spring-framework-reference/html/transaction.html)

<aop:config>
  <aop:pointcut id="fooServiceOperation" expression="execution(* x.y.service.FooService.*(..))"/>
  <aop:advisor advice-ref="txAdvice" pointcut-ref="fooServiceOperation"/>
</aop:config>
<tx:advice id="txAdvice" transaction-manager="txManager"> 
  <tx:attributes> 
    <!-- all methods starting with 'get' are read-only --> 
    <tx:method name="get*" read-only="true"/> 
    <!-- other methods use the default transaction settings --> 
    <tx:method name="*"/>
  </tx:attributes> 
</tx:advice>

Transaction Propagation: see http://static.springsource.org/spring/docs/3.1.x/javadoc-api/org/springframework/transaction/annotation/Propagation.html

eg

@Transactional(propagation=Propagation.REQUIRED)

  • REQUIRED – if no tx in progress oen is started. If in progress, tx is joined (THIS IS THE DEFAULT)
  • REQUIRES_NEW – new tx is started whether or not one already active. if previous tx active, it is suspended and new transaction started. if new transaction fails it does not have any impact on prior suspended tx
  • SUPPORTS – if tx active it’s used, it no transaction continues without a tx
  • NOT_SUPPORTED – no tx supported. if tx active, tx is suspended, code completes without tx. On completion returns to caller and previous tx is resumed
  • MANDATORY – tx must be active, and is joined when code called. if no tx active when code is called an exception is thrown
  • NESTED – if tx active, a new child transaction is created. if nested/child transaction fails, this forces parent transaction to also fail. if no tx active, creates a new one (no equivalent in EE?)
  • NEVER – rarely used. opposite of MANDATORY. if no tx active, continue. if tx active, throw exception

Rolling back a transaction

  • RuntimeExceptions always cause a transaction to rollback if not caught and consumed/handled
  • Exception to this is if default behavior is changed by using @Transactional(rollbackFor=ExceptionName.class) to indicate which specific exceptions will cause a rollback

Using @Transactional with JUnits

  • by default, an @Transactional @Test will always rollback db changes on test method completion to leave db intact/unchanged