SSH Spring transaction management

The transaction configuration in the Spring configuration file always consists of three components, namely DataSource, TransactionManager and proxy mechanism. No matter which configuration method is used, generally only the proxy mechanism changes. The two parts of DataSource and TransactionManager will only change according to the data access method. For example, when using Hibernate for data access, the DataSource is actually SessionFactory, and the implementation of TransactionManager is HibernateTransactionManager. Let’s take a look at the specific configurations of the three declarative transactions:

Public configuration:

<!-- Configure sessionFactory -->
<bean id="sessionFactory" class="org.springframework.orm.hibernate3.annotation.AnnotationSessionFactoryBean">
    <property name="configLocation">
        <value>classpath:config/hibernate.cfg.xml</value>
    </property>
    <property name="packagesToScan">
        <list>
            <value>com.entity</value>
        </list>
    </property>
</bean>

<!-- Configure transaction manager (declarative transaction) -->
<bean id="transactionManager" class="org.springframework.orm.hibernate3.HibernateTransactionManager">
    <property name="sessionFactory" ref="sessionFactory"></property>
</bean>

<!-- Configure DAO -->
<bean id="userDao" class="com.dao.UserDaoImpl">
    <property name="sessionFactory" ref="sessionFactory"></property>
</bean>

The first method is to use the tx tag:

<!-- The first way to configure transactions, tx-->
<tx:advice id="txadvice" transaction-manager="transactionManager">
    <tx:attributes>
        <tx:method name="add*" propagation="REQUIRED" rollback-for="Exception" />
        <tx:method name="modify*" propagation="REQUIRED" rollback-for="Exception" />
        <tx:method name="del*" propagation="REQUIRED" rollback-for="Exception"/>
        <tx:method name="*" propagation="REQUIRED" read-only="true"/>
    </tx:attributes>
</tx:advice>

<aop:config>
    <aop:pointcut id="daoMethod" expression="execution(* com.dao.*.*(..))"/>
    <aop:advisor pointcut-ref="daoMethod" advice-ref="txadvice"/>
</aop:config>

expression=”execution( com.dao..(..))” where the first represents the return value, the second represents the dao sub-package, and the third Each represents the method name, and “(..)” represents the method parameters.

Second, use proxy method:

<!-- The second way to configure transactions, proxy -->
<bean id="transactionProxy"
    class="org.springframework.transaction.interceptor.TransactionProxyFactoryBean" abstract="true">
    <property name="transactionManager" ref="transactionManager"></property>
    <property name="transactionAttributes">
        <props>
            <prop key="add*">PROPAGATION_REQUIRED, -Exception</prop>
            <prop key="modify*">PROPAGATION_REQUIRED, -Exception</prop>
            <prop key="del*">PROPAGATION_REQUIRED, -Exception</prop>
            <prop key="*">PROPAGATION_REQUIRED, readOnly</prop>
        </props>
    </property>
</bean>
<bean id="userDao" parent="transactionProxy">
    <property name="target">
        <!-- How to use beans instead of refs-->
        <bean class="com.dao.UserDaoImpl">
            <property name="sessionFactory" ref="sessionFactory"></property>
        </bean>
    </property>
</bean> 

Set the abstract attribute of transactionProxy to “true”, and then set the parent attribute of the specific Dao to “transactionProxy” to simplify the code.

Third, use interceptors:

<!-- The third way to configure transactions, interceptor (not commonly used)-->
<bean id="transactionInterceptor" class="org.springframework.transaction.interceptor.TransactionInterceptor">
    <property name="transactionManager" ref="transactionManager"></property>
    <property name="transactionAttributes">
        <props>
            <prop key="add*">PROPAGATION_REQUIRED, -Exception</prop>
            <prop key="modify*">PROPAGATION_REQUIRED, -Exception</prop>
            <prop key="del*">PROPAGATION_REQUIRED, -Exception</prop>
            <prop key="*">PROPAGATION_REQUIRED, readOnly</prop>
        </props>
    </property>
</bean>
<bean id="proxyFactory" class="org.springframework.aop.framework.autoproxy.BeanNameAutoProxyCreator">
    <property name="interceptorNames">
        <list>
            <value>transactionInterceptor</value>
        </list>
    </property>
    <property name="beanNames">
        <list>
            <value>*Dao</value>
        </list>
    </property>
</bean> 

Detailed explanation of Spring transaction types:

  • PROPAGATION_REQUIRED–Supports the current transaction. If there is no current transaction, create a new transaction. This is the most common choice.
  • PROPAGATION_SUPPORTS–Supports the current transaction. If there is no current transaction, it will be executed in a non-transactional manner.
  • PROPAGATION_MANDATORY–Supports the current transaction. If there is no current transaction, an exception will be thrown.
  • PROPAGATION_REQUIRES_NEW–Create a new transaction. If a transaction currently exists, suspend the current transaction.
  • PROPAGATION_NOT_SUPPORTED–Perform operations in a non-transactional manner. If a transaction currently exists, suspend the current transaction.
  • PROPAGATION_NEVER–Execute in a non-transactional manner, throw an exception if a transaction currently exists.
  • PROPAGATION_NESTED–If a transaction currently exists, execute within a nested transaction. If there is no current transaction, perform similar operations to PROPAGATION_REQUIRED.
  • readOnly–The readOnly flag in the transaction attribute indicates that the corresponding transaction should be optimized as a read-only transaction. If the value is true, it will tell Spring that there is no insert or update in this method. You only need to provide a read-only database Connection. This execution efficiency will be higher than the read-write Connection, so this is an optimization tip. In some cases, some transaction strategies can have a significant optimization effect, such as avoiding dirty checking (trying to “refresh”) when using Object/Relational mapping tools (such as Hibernate or TopLink).

When using annotations, it should be noted that when using annotations, you need to add a sentence to the Spring configuration file: , which is used to enable annotations. The specific configuration is as follows:

<!--Enable annotation mode-->
<context:annotation-config />

<!-- Configure sessionFactory -->
<bean id="sessionFactory" class="org.springframework.orm.hibernate3.annotation.AnnotationSessionFactoryBean">
    <property name="configLocation">
        <value>classpath:config/hibernate.cfg.xml</value>
    </property>
    <property name="packagesToScan">
        <list>
            <value>com.entity</value>
        </list>
    </property>
</bean>

<!-- Configure transaction manager -->
<bean id="transactionManager" class="org.springframework.orm.hibernate3.HibernateTransactionManager">
    <property name="sessionFactory" ref="sessionFactory"></property>
</bean>

<!-- The fourth way to configure transactions, annotations -->
<tx:annotation-driven transaction-manager="transactionManager"/> 

Annotation file:

package com.dao;

import org.springframework.orm.hibernate3.HibernateTemplate;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;

import com.entity.User;

@Transactional
public class UserDaoImpl_BAK extends HibernateTemplate {

    @Transactional(propagation=Propagation.REQUIRED,rollbackForClassName="Exception")
    public void addUser(User user) throws Exception {
        this.save(user);
    }

    @Transactional(propagation=Propagation.REQUIRED,rollbackForClassName="Exception")
    public void modifyUser(User user) {
        this.update(user);
    }

    @Transactional(propagation=Propagation.REQUIRED,rollbackForClassName="Exception")
    public void delUser(String username) {
        this.delete(this.load(User.class, username));
    }

    @Transactional(readOnly=true)
    public void selectUser() {

    }

} 

@Transactional in the class header is the default transaction configuration. If the method does not have its own transaction type, it will be the default transaction. If it has its own configuration, it will be its own configuration.

The most commonly used of the above four configuration methods are the first and second. The third is an older method, and the annotation method is not suitable for larger projects. It is still very good for simple small projects. Its characteristics Just plain and simple. Each method has its own characteristics and applicable environments. There is no absolute good or bad, but the first two are used more in actual work.