spring事務介紹

1、spring事務介紹

spring事務優勢

  • 對不一樣的api進行統一編程模型,如JTA,JDBC,Hibernate,JPA,JDO...
  • 支持聲明式事務
  • 簡化編程式事務api
  • 對spring數據層的完美抽象

spring事務的傳播性

PROPAGATION_REQUIRED 若是當前沒有事務,就新建一個事務,若是已經存在一個事務中,加入到這個事務中
html

PROPAGATION_REQUIRES_NEW 每個受影響的事務做用域都使用徹底 獨立的事務.物理上的事務就不一樣了而且能夠獨立的提交或者回滾, 外部事物不會影響到內部事務的回滾 狀態
java

PROPAGATION_NESTED 事務嵌套 子事務是父事務的一部分,父事務失敗則所有回滾,若是子事務失敗,則回滾到進入子事務以前的狀態spring

官網好像只列出了這幾個,可是不少博客都說有9種,不過咱們大部分都用的Required級別,其它的就不深究了,若是須要進一步瞭解可參考 https://my.oschina.net/dongli...數據庫

2、如何使用spring事務

聲明式事務

理解聲明式事務實現機制

註解事務的最基本是利用了spring的aop實現,調用者調用的實則是目標類的代理類,代理類有事務的攔截器Interceptor, TransactionInterceptor 來實現對應的事務處理express

xml配置方式apache

<!-- 事務化配置 -->
    <tx:advice id="txAdvice" transaction-manager="txManager">
        <!-- 事務語義... -->
        <tx:attributes>
            <!-- 全部用'get'開頭的方法都是隻讀的 -->
            <tx:method name="get*" read-only="true"/>
            <!-- 其餘的方法使用默認的事務配置(看下面) -->
            <tx:method name="*"/>
        </tx:attributes>
    </tx:advice>

    <!-- 定義切面配置 -->
    <aop:config>
        <!-- FooService 下的全部方法-->
        <aop:pointcut id="fooServiceOperation" expression="execution(* x.y.service.FooService.*(..))"/>
        <aop:advisor advice-ref="txAdvice" pointcut-ref="fooServiceOperation"/>
    </aop:config>

    <!-- DataSource數據源配置 -->
    <bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close">
        <property name="driverClassName" value="oracle.jdbc.driver.OracleDriver"/>
        <property name="url" value="jdbc:oracle:thin:@rj-t42:1521:elvis"/>
        <property name="username" value="scott"/>
        <property name="password" value="tiger"/>
    </bean>

    <!-- 聲明事務管理器實現 -->
    <bean id="txManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
        <property name="dataSource" ref="dataSource"/>
    </bean>

tx-method配置項說明編程

配置項 是否必須 默認值 描述
name
propagation REQUIRED 事務傳播行爲,參考上文描述
isolation DEFAULT 隔離級別 default使用數據庫默認的事務隔離級別
timeout -1 事務超時時間 單位 秒
read-only false 事務級別是否只讀
rollback-for ----- 指定回滾異常類型
no-rollback-for ----- 指定什麼異常類型不回滾

isolation 可選值
DEFAULT 使用當前數據庫默認的事務界別
READ_UNCOMMITTED
READ_COMMITTED
REPEATABLE_READ 可重複讀
SERIALIZABLEapi

註解方式(經常使用)mybatis

配置的方式是採用通配符的方式進行事務切入,不夠靈活,在實際開發中註解的方式用的較多,配置可參考下面oracle

<!-- 數據源 -->
<bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close">
        <property name="driverClassName" value="oracle.jdbc.driver.OracleDriver"/>
        <property name="url" value="jdbc:oracle:thin:@rj-t42:1521:elvis"/>
        <property name="username" value="scott"/>
        <property name="password" value="tiger"/>
    </bean>
<!-- 使用註解配置的事務行爲生效 -->
    <tx:annotation-driven transaction-manager="txManager"/>
<!--事務管理器-->    
<bean id="txManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">        <property name="dataSource" ref="dataSource"/>
    </bean>

<!--開啓事務註解配置 -->
<tx:annotation-driven transaction-manager="txManager"/>

須要事務的方法加上註解便可

//註解加到類上,則該類裏全部public方法啓用事務
//註解加在方法上,則只有方法啓用事務
@Transactional
public class DefaultFooService implements FooService {

    Foo getFoo(String fooName);

    Foo getFoo(String fooName, String barName);

    void insertFoo(Foo foo);

    void updateFoo(Foo foo);
}

方法可見性和@Transactional
當使用代理時, 你應該只給public可見性的方法添加@Transactional註解. 若是你給protected, private或者包訪問的方法添加了@Transactional註解, 不會產生錯誤, 可是事務不生效. 若是你須要給非公開的方法添加註解能夠參考其它文檔,此處不作概述

多數據源,多事務

<!-- 同上,不一樣的dataSource配置不一樣的txManager -->

<tx:annotation-driven transaction-manager="txManager"/>
<tx:annotation-driven transaction-manager="txManager1"/>
<tx:annotation-driven transaction-manager="txManager2"/>
//名字和事務管理器同名便可
@Transactional("txManager1")
public class DefaultFooService implements FooService {

    Foo getFoo(String fooName);

    Foo getFoo(String fooName, String barName);

    void insertFoo(Foo foo);

    void updateFoo(Foo foo);
}

也能夠給txManager加上別名

<!--事務管理器-->    
<bean id="txManager1" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">        
      <qualifier value="order"/>
      <property name="dataSource" ref="dataSource"/>
    </bean>

<bean id="txManager2" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">        
      <qualifier value="account"/>
      <property name="dataSource" ref="dataSource"/>
    </bean>

<tx:annotation-driven transaction-manager="txManager1"/>
<tx:annotation-driven transaction-manager="txManager2"/>
//名字和事務管理器的qualifier相同便可
@Transactional("order")
public class DefaultFooService implements FooService {

    Foo getFoo(String fooName);

    Foo getFoo(String fooName, String barName);

    void insertFoo(Foo foo);

    void updateFoo(Foo foo);
}

*使用註解的方式,注意下面這種情形,防止事務不生效
1.不要對本身要進行事務控制的代碼進行try catch,spring的事務觸發是執行體出現異常,若是本身的程序catch住了異常,spring事務管理器覺得執行成功,回滾不生效

//錯誤示例
 @Transactional
    public void update2(String name){
        try {
            jdbcTemplate.execute("UPDATE t_menua SET  mname='"+name+"' WHERE mid=106 ");
        } catch (DataAccessException e) {
            e.printStackTrace();
        }
    }
  1. 嵌套執行,A 調用 B , A沒有加事務註解,事務不生效
//錯誤案例
   @Transactional
    public void update2(String name){
        jdbcTemplate.execute("UPDATE t_menua SET  mname='"+name+"' WHERE mid=106 ");
    }

    public void update3(String name) {
        this.update2(name);
        throw new RuntimeException();
    }

調用堆棧以下

//事務生效
@Transactional
    public void update2(String name){
        jdbcTemplate.execute("UPDATE t_menua SET  mname='"+name+"' WHERE mid=106 ");
    }

    @Transactional
    public void update3(String name) {
        this.update2(name);
        throw new RuntimeException();
    }

調用堆棧以下

你們對比能夠發現,第一種的執行棧裏壓根就沒有事務攔截器,因此事務沒有生效

編程式事務

spring 配置

<!-- dataSource 配置同上-->
<!-- 事務管理器 配置同上  管理器名字 txManage-->

<bean id="transactionTemplate" class="org.springframework.transaction.support.TransactionTemplate" >
        <property name="transactionManager" ref="txManage" />
    </bean>

java代碼

public class LocalDataService {


    /**
     * 編程式事務模板
     */
    @Resource
    private TransactionTemplate transactionTemplate;


    /**
     * dao層執行體,能夠是hibernate,mybatis等其它db框架
     */
    @Resource
    private JdbcTemplate jdbcTemplate;


    /**
     * 修改數據
     */
    public void update(final String name){

        transactionTemplate.execute(new TransactionCallback<Integer>() {
            public Integer doInTransaction(TransactionStatus transactionStatus) {
                jdbcTemplate.execute("UPDATE t_menua SET  mname='"+name+"' WHERE mid=106 ");
                return 1;
            }
        });

        throw new RuntimeException();
    }
}

transactionTemplate 官方有兩種

TransactionTemplate
PlatformTransactionManager

Spring通常都推薦使用TransactionTemplate來進行編程式事務管理. 第二種方式有點相似於使用JTA的 UserTransaction接口

參考文檔
spring中文文檔 http://spring.cndocs.tk/trans...

相關文章
相關標籤/搜索