Spring declarative Transaction Management example

Source: Internet
Author: User

Spring does not directly implement transaction management. It only manages which methods require transactions and calls the underlying transaction manager through AOP for transaction management. the classes that need transaction management are created by the spring proxy. The proxy class implements transaction management by inserting the pre-processing process (start transaction) and post-processing process (commit or rollbak) before and after the connection point.

Spring defines what kind of methods should be pre-processed by the Transaction Manager (platformtransactionmanager). When the transaction method is declared to be called, it calls the Commit (transactionstatus status) of platformtransactionmanager) or rollback (transactionstatus status), commit and rollback are implemented by a specific transactionmanager. For example, the actual transaction management of datasourcetransactionmanager still relies on the commit or rollback of the connection. (Image Source: Spring
In action)

1. First, use an example to illustrate the JDBC datasourcetransactionmanager: the code structure is to access the DB in Dao, access Dao in the service class, and configure the transaction in the service class.
The spring configuration is as follows:

<beans xmlns="http://www.springframework.org/schema/beans"    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"    xmlns:p="http://www.springframework.org/schema/p"    xmlns:aop="http://www.springframework.org/schema/aop"    xmlns:tx="http://www.springframework.org/schema/tx"    xmlns:jee="http://www.springframework.org/schema/jee"    xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd    http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-3.0.xsd    http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-3.0.xsd    http://www.springframework.org/schema/jee http://www.springframework.org/schema/jee/spring-jee-3.0.xsd    http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.0.xsd"    default-autowire="byName">    <bean id="jdbcTestDAO" class="com.test.spring.tx.jdbc.JDBCTestDAO">        <property name="dataSource" ref="dataSource" />    </bean>    <bean id="buzSingleService" class="com.test.spring.tx.jdbc.BuzSingleService"/>    <bean id="buzMultipleService" class="com.test.spring.tx.jdbc.BuzMultipleService"/>            <bean id="dataSource"        class="org.springframework.jdbc.datasource.DriverManagerDataSource">        <property name="driverClassName" value="oracle.jdbc.driver.OracleDriver" />        <property name="url" value="jdbc:oracle:thin:@147.151.240.XX:1521:ORCL" />        <property name="username" value="but" />        <property name="password" value="but" />    </bean>    <tx:advice id="txAdvice" transaction-manager="txManager">        <tx:attributes>            <tx:method name="*" propagation="REQUIRED"/>        </tx:attributes>    </tx:advice>    <bean id="txManager"        class="org.springframework.jdbc.datasource.DataSourceTransactionManager">        <property name="dataSource" ref="dataSource" />    </bean>    <aop:config>        <aop:pointcut id="serviceOperation"            expression="execution(* com.test.spring.tx.jdbc.*Service*.*(..))" />        <aop:advisor advice-ref="txAdvice" pointcut-ref="serviceOperation" />    </aop:config>    </beans>

** The transaction is configured as expression = "execution (* COM. test. spring. TX. JDBC. * Service *. *(..)) ", indicating COM. test. spring. TX. all methods with the service class name in the JDBC package must be run in the transaction.
DAO class:

public class JDBCTestDAO {    private JdbcTemplate jdbcTemplate;    public void setDataSource(DataSource dataSource) {        this.jdbcTemplate = new JdbcTemplate(dataSource);    }    public void testInsert(int id, String val) {        this.jdbcTemplate.update("insert into A (ID, VAL) values (?, ?)", id, val);    }    public void testUpdate(int id, String val) {        this.jdbcTemplate.update("update A set val = ? where id = ?", val, id);    }    public void testDelete(int id) {        this.jdbcTemplate.update("delete from A where id=?", id);    }}

One service class is as follows:

public class BuzSingleService {    @Autowired    JDBCTestDAO jdbcTestDAO;    public void testTX1() throws Exception {        jdbcTestDAO.testInsert(0, "val0");        jdbcTestDAO.testInsert(1, "val1");        }    public void testTX2() throws Exception {        jdbcTestDAO.testInsert(2, "runtime exception nullpoint");        String nullStr = null;        nullStr.length();    }    public void testTX3() throws Exception {        jdbcTestDAO.testInsert(3, "checked exception CheckedException");        throw new CheckedException();    }    public JDBCTestDAO getJdbcTestDAO() {        return jdbcTestDAO;    }    public void setJdbcTestDAO(JDBCTestDAO jdbcTestDAO) {        this.jdbcTestDAO = jdbcTestDAO;    }}

If every method in this service class is called by a client code (the client code is not run in a spring-configured transaction ), therefore, each method is determined by the propagation = "required" configuration. Here, we only describe the Spring transaction management as a whole. We will not introduce other propagation configurations ). for example, the following code assumes that it is run in another main function:
A. The database inserts two pieces of data, serv. testtx1 as a whole transaction.
Buzsingleservice serv = (buzsingleservice) CTX. getbean ("buzsingleservice ");
Serv. testtx1 ();
B, Serv. the "RunTime" exception (runtimeexception) is thrown in the testtx2 () method, because the caller is not running in the transaction, Serv. testtx1 (); and Serv. testtx2 (); is independent of each other, and two pieces of data are still inserted into the database.
Buzsingleservice serv = (buzsingleservice) CTX. getbean ("buzsingleservice ");
Serv. testtx1 ();
Serv. testtx2 ();
C. The testtx1 method is changed to the following: after the second data is inserted, a "RunTime" exception is thrown. No data is inserted into the database, and all database operations in testtx1 are in the same transaction.

    public void testTX1() throws Exception {        jdbcTestDAO.testInsert(0, "val0");        jdbcTestDAO.testInsert(1, "val1");        String nullStr = null;        nullStr.length();    }

D. By default, a non-"RunTime" exception type is thrown and the transaction is not rolled back. The exception is thrown to the caller, but the transaction has been committed.
Checkedexception is a user-defined exception: public class checkedexception extends exception {}
Buzsingleservice serv = (buzsingleservice) CTX. getbean ("buzsingleservice ");
Serv. testtx3 ();
E. Call the two methods of buzsingleservice in a transaction method. The two called methods are in the same transaction:

public class BuzMultipleService {    @Autowired    BuzSingleService buzSingleService;    public void testTX() throws Exception {        buzSingleService.testTX1();        buzSingleService.testTX2();        String nullStr = null;        nullStr.length();    }    public BuzSingleService getBuzSingleService() {        return buzSingleService;    }    public void setBuzSingleService(BuzSingleService buzSingleService) {        this.buzSingleService = buzSingleService;    }    }

The following is called in a main method. No data is inserted into the database. because buzmultipleservice. the testtx method is in the transaction, and the buzsingleservice. testtx1 and buzsingleservice. if testtx2 is called in a transaction method, it forms a whole transaction. (changes are related to propagation settings)
Buzmultipleservice serv = (buzmultipleservice) CTX. getbean ("buzmultipleservice ");
Serv. testtx ();
2. After Hibernate is integrated, the transaction management method through hibernatetransactionmanager is similar to JDBC. The spring configuration is as follows:

    <bean id="plainHibernateDAO" class="com.test.spring.tx.hibernate.PlainHibernateDAO">        <property name="sessionFactory" ref="mySessionFactory" />    </bean>    <bean id="hbSingleService" class="com.test.spring.tx.hibernate.HBSingleService"/>    <bean id="hbMultipleService" class="com.test.spring.tx.hibernate.HBMultipleService"/>    <bean id="mySessionFactory"        class="org.springframework.orm.hibernate3.LocalSessionFactoryBean">        <property name="configLocation" value="classpath:config/Hibernate.cfg.xml" />        </bean>       <bean id="txManager"        class="org.springframework.orm.hibernate3.HibernateTransactionManager">        <property name="sessionFactory" ref="mySessionFactory" />    </bean>        <tx:advice id="txAdvice" transaction-manager="txManager">        <tx:attributes>            <tx:method name="*" propagation="REQUIRED"/>        </tx:attributes>    </tx:advice>    <aop:config>        <aop:pointcut id="hbOperation"            expression="execution(* com.test.spring.tx.hibernate.*Service*.*(..))" />        <aop:advisor advice-ref="txAdvice" pointcut-ref="hbOperation" />    </aop:config>

Note that the <property name = "current_session_context_class"> thread </property> cannot be specified in the hibernate configuration file.
** You can configure multiple transactionmanagers in the same configuration file for different transactions. For example, an hbtxmanager (specified by ID) is used to manage hibernate transactions, and an jmstxmanager is used to manage JMS transactions.
3. Manage JMS transactions. The MQ here is activemq. The features of transaction commit and rollback are the same as those in the JDBC example. The spring configuration is as follows:

<bean id="jmsAccessor" class="com.test.spring.tx.jms.JmsAccessor">        <property name="jmsTemplate" ref="jmsTemplate"/>        <property name="destination" ref="destination"/>    </bean>    <bean id="jmsSingleService" class="com.test.spring.tx.jms.JMSSingleService"/>    <bean id="jmstxManager" class="org.springframework.jms.connection.JmsTransactionManager">        <property name="connectionFactory" ref="jmsConnectionFactory"/>    </bean>    <bean id="jmsConnectionFactory" class="org.apache.activemq.ActiveMQConnectionFactory">        <property name="brokerURL" value="tcp://localhost:61616"/>            </bean>    <bean id="destination" class="org.apache.activemq.command.ActiveMQQueue">        <constructor-arg index="0" value="example.yorker" />    </bean>    <bean id="jmsTemplate" class="org.springframework.jms.core.JmsTemplate">       <property name="connectionFactory" ref="jmsConnectionFactory"/>       <property name="defaultDestination" ref="destination"/>       <property name="receiveTimeout" value="10000"/>    </bean>    <tx:advice id="jmstxAdvice" transaction-manager="jmstxManager">        <tx:attributes>            <tx:method name="*" propagation="REQUIRED"/>        </tx:attributes>    </tx:advice>    <aop:config>        <aop:pointcut id="jmsOperation"            expression="execution(* com.test.spring.tx.jms.*Service*.*(..))" />        <aop:advisor advice-ref="jmstxAdvice" pointcut-ref="jmsOperation" />    </aop:config>

Java classes accessed by JMS are as follows:

public class JmsAccessor {    JmsTemplate jmsTemplate;    Destination destination;    public void send() {        MessageCreator messageCreator = new MessageCreator() {            public Message createMessage(Session session) {                TextMessage message = null;                try {                    message = session.createTextMessage("Hello message");                } catch (JMSException e) {                    e.printStackTrace();                }                return message;            }        };        jmsTemplate.send(this.destination, messageCreator);    }    public void receive() {        TextMessage message = (TextMessage) jmsTemplate.receive();        try {            System.out.println("Message received:" + message.getText());        } catch (JMSException e) {            e.printStackTrace();        }    }    public JmsTemplate getJmsTemplate() {        return jmsTemplate;    }    public void setJmsTemplate(JmsTemplate jmsTemplate) {        this.jmsTemplate = jmsTemplate;    }    public Destination getDestination() {        return destination;    }    public void setDestination(Destination destination) {        this.destination = destination;    }}

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.