實現spring事務的四種方式


用一個銀行賬號轉錢的案例來說明spring事務的實現。
在轉錢過程中,一個賬號錢增加,另一個減少,那么當有異常產生時,就會出現錢轉丟了的現象
一個減少了,而另一個沒有增加,這個時候就需要把這兩個行為綁定到一起,要么同時發生,要么都不發生
這就用到了事務,事務就是指在邏輯上的一組操作,這組操作要么全部成功,要么全部失敗
實現spring事務的四種方式分別為:
(1)編程式事務管理:需要手動編寫代碼,在實際開發中很少使用
(2)聲明式事務管理:
(2.1)基於TransactionProxyFactoryBean的方式,需要為每個進行事務管理的類做相應配置
(2.2)基於AspectJ的XML方式,不需要改動類,在XML文件中配置好即可
(2.3)基於注解的方式,配置簡單,需要在業務層類中添加注解
(2.2)和(2.3)在開發中使用比較多,前者配置一目了然,可以在XML文件中得到所有信息,后者配置簡單方便

需要做的一些准備工作:

 

1.在數據庫中新建一張account數據表

SQL腳本:

CREATE TABLE `account` (

  `id` int(11) NOT NULL AUTO_INCREMENT,

  `name` varchar(20) NOT NULL,

  `money` double DEFAULT NULL,

  PRIMARY KEY (`id`)

) ENGINE=InnoDB AUTO_INCREMENT=4 DEFAULT CHARSET=utf8;

INSERT INTO `account` VALUES ('1', 'aaa', '1000');

INSERT INTO `account` VALUES ('2', 'bbb', '1000');

INSERT INTO `account` VALUES ('3', 'ccc', '1000');

2.需要引入的Jar包

3.為數據庫連接准備的配置文件- jdbc.properties

使用c3p0數據庫連接池

jdbc.driverClass=com.mysql.jdbc.Driver
jdbc.url=jdbc\:mysql\://127.0.0.1\:3306/test
jdbc.username=root
jdbc.password=

4.創建兩個接口
AccountDao:數據庫操作
public interface AccountDao {public void outMoney(String out,Double money);public void inMoney(String in,Double money);
}
AccountService:邏輯處理操作
public interface AccountService {/*** * @param out 轉出賬號* @param in  轉入賬號* @param money 轉賬金額*/public void transfer(String out,String in,Double money);
}
5.創建以上兩個接口的實現類
import org.springframework.jdbc.core.support.JdbcDaoSupport;

 

public class AccountDaoImpl extends JdbcDaoSupport implements AccountDao{

    

    public void outMoney(String out, Double money) {

        String sql="update account set money=money-? where name=?";

        this.getJdbcTemplate().update(sql,money,out);

    }

 

    public void inMoney(String in, Double money) {

        String sql="update account set money=money+? where name=?";

        this.getJdbcTemplate().update(sql,money,in);

    }

}
public class AccountServiceImpl implements AccountService{

 

    private AccountDao accountDao;

    

    public void setAccountDao(AccountDao accountDao) {

        this.accountDao = accountDao;

    }

 

    public void transfer(String out,String in,Double money) {

        

        accountDao.outMoney(out, money);

        accountDao.inMoney(in, money);    

    }        

}

6.測試類(使用spring加JUnit4整合測試)

import javax.annotation.Resource;

import org.junit.Test;

import org.junit.runner.RunWith;

import org.springframework.test.context.ContextConfiguration;

import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;

 

@RunWith(SpringJUnit4ClassRunner.class)

@ContextConfiguration("classpath:applicationContext.xml")//引入xml文件

public class TestDemo1 {

    

    @Resource(name="accountService")//得到bean id為accountService的對象

    private AccountService accountService;

    

    @Test

    public void demo1(){

        accountService.transfer("aaa", "bbb", 200d);

    }    

}

7.xml文件 - applicationContext.xml:

<?xml version="1.0" encoding="UTF-8"?>

<beans xmlns="http://www.springframework.org/schema/beans"

     xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"

     xmlns:context="http://www.springframework.org/schema/context"

     xmlns:aop="http://www.springframework.org/schema/aop"

     xmlns:tx="http://www.springframework.org/schema/tx"

     xmlns:task="http://www.springframework.org/schema/task"

     xsi:schemaLocation="http://www.springframework.org/schema/beans

         http://www.springframework.org/schema/beans/spring-beans-3.1.xsd

         http://www.springframework.org/schema/context

         http://www.springframework.org/schema/context/spring-context-3.1.xsd

         http://www.springframework.org/schema/aop

         http://www.springframework.org/schema/aop/spring-aop-3.1.xsd

         http://www.springframework.org/schema/tx

         http://www.springframework.org/schema/tx/spring-tx-3.1.xsd

         http://www.springframework.org/schema/task

         http://www.springframework.org/schema/task/spring-task-3.1.xsd">

    

    <!-- 引入外部的配置文件 -->

    <context:property-placeholder location="classpath:jdbc.properties"/>

 

    <!-- 配置c3p0連接池 -->

    <bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource">

        <property name="driverClass" value="${jdbc.driverClass}"/>

        <property name="jdbcUrl" value="${jdbc.url}"/>

        <property name="user" value="${jdbc.username}"/>

        <property name="password" value="${jdbc.password}"/>

    </bean>

    

    <bean id="accountService" class="demo1.AccountServiceImpl">

        <property name="accountDao" ref="accountDao"/>

    </bean>

    

    <bean id="accountDao" class="demo1.AccountDaoImpl">

        <property name="dataSource" ref="dataSource"/>

    </bean>

    

</beans>

代碼實現方式:

 

(1)編程式事務管理

 

ServiceImpl類:

import org.springframework.transaction.TransactionStatus;

import org.springframework.transaction.support.TransactionCallbackWithoutResult;

import org.springframework.transaction.support.TransactionTemplate;

public class AccountServiceImpl implements AccountService{

 

    private AccountDao accountDao;

    

    public void setAccountDao(AccountDao accountDao) {

        this.accountDao = accountDao;

    }

 

    /**

     * 注入事務管理的模板

     * 在xml文件中添加Property

     * <property name="transactionTemplate" ref="transactionTemplate"/>

     */

    private TransactionTemplate transactionTemplate;

    

    public void setTransactionTemplate(TransactionTemplate transactionTemplate) {

        this.transactionTemplate = transactionTemplate;

    }

 

    public void transfer(final String out,final String in,final Double money) {

        /**

         * 在這里面進行事務操作

         * 因為需要在匿名內部類中使用參數,所以給參數加上final關鍵字

         */

        transactionTemplate.execute(new TransactionCallbackWithoutResult(){

 

            @Override

            protected void doInTransactionWithoutResult(

                    TransactionStatus transactionStatus) {

                accountDao.outMoney(out, money);

            

                accountDao.inMoney(in, money);        

            }    

        });

    

    }        

}

xml文件中需要配置事務管理器,無論使用哪一種方式,都需要在xml文件中配置事務管理器,將事務管理器注入到模板中,而該模板又會自動注入到accountService中,業務邏輯處理都放在了execute方法中。

 

<!--spring事務編程式 -->

<!-- 配置事務管理器  -->

<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">

    <property name="dataSource" ref="dataSource"/>

</bean>

    

<!-- 定義事務管理的模板 :Spring為了簡化事務管理的代碼而提供的類  -->

<bean id="transactionTemplate" class="org.springframework.transaction.support.TransactionTemplate">

    <property name="transactionManager" ref="transactionManager"/>

</bean> 
在DaoImpl類中,繼承了JdbcDaoSupport類,可以省去jdbc復雜的代碼
在XML文件配置中,注入dataSource用來獲取數據庫的連接

(2.1)基於TransactionProxyFactoryBean的方式
采用spring-aop的方式,需要用到代理模式
XML文件:
<!-- 配置事務管理器  -->

<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">

    <property name="dataSource" ref="dataSource"/>

</bean>

    

<!-- 配置業務層代理: -->

<bean id="accountServiceProxy" 

    class="org.springframework.transaction.interceptor.TransactionProxyFactoryBean">

    <!-- 配置目標對象 -->

    <property name="target" ref="accountService"/>

    <!-- 注入事務管理器  -->

    <property name="transactionManager" ref="transactionManager"/>

    <!-- 注入事務屬性 -->

    <property name="transactionAttributes">

        <props>

        <!-- 

           格式 ,key為方法名稱

           PROPAGATION:事務的傳播行為

           ISOLATION:事務的隔離級別

           readOnly:只讀

           Exception:發生哪些異常,回滾事務

           +Exception:發生哪些異常不回滾

         -->

            <prop key="transfer">PROPAGATION_REQUIRED</prop>

        </props>

    </property>

</bean>
在測試類中需自動注入的bean-id就不再是accountService了,而是代理類accountServiceProxy
此時代理類和被代理類實現了共同的接口,AccountService,有關代理模式請看:代理模式
@Resource(name="accountServiceProxy")
private AccountService accountService;
 
(2.2)基於AspectJ的XML方式
XML文件:
<!-- 配置事務管理器 -->

<bean id="transactionManager" 

    class="org.springframework.jdbc.datasource.DataSourceTransactionManager">

    <property name="dataSource" ref="dataSource"/>

</bean>

    

<!-- 配置的事務的通知 -->

<tx:advice id="txAdvice" transaction-manager="transactionManager">

    <tx:attributes>

        <!-- 

        propagation:事務傳播行為

        isolation:事務隔離級別

        read-only:只讀

        rollback-for:發生哪些異常回滾

        no-rollback-for:發生哪些異常不回滾

        timeout:有效期

         -->

        <tx:method name="transfer" propagation="REQUIRED"/>

    </tx:attributes>

</tx:advice>

    

<!-- 配置切面 -->

<aop:config>

    <aop:pointcut expression="execution(* demo3.AccountService.*(..))" id="pointcut1"/>

    <aop:advisor advice-ref="txAdvice" pointcut-ref="pointcut1"/>

</aop:config>

(2.3)基於注解的方式,配置簡單,需要在業務層類中添加注解

<!-- 配置事務管理器 -->

<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">

    <property name="dataSource" ref="dataSource"/>

</bean>

    

<!-- 開啟注解事務 -->

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

在serviceImpl類中需要添加注解,參數和上面同理

@Transactional(propagation=Propagation.REQUIRED)

我這兒整理了比較全面的JAVA相關的面試資料,


需要領取面試資料的同學,請加群:473984645

 

 

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM