Spring高級事務管理難點剖析

1Spring事務傳播行爲

所謂事務傳播行爲就是多個事務方法相互調用時,事務如何在這些方法間傳播。Spring支持7種事務傳播行爲java

PROPAGATION_REQUIRED(加入已有事務)spring

若是當前沒有事務,就新建一個事務,若是已經存在一個事務中,加入到這個事務中。這是最多見也是默認的方式。數據庫

PROPAGATION_SUPPORTS(跟隨環境)緩存

支持當前事務,若是當前沒有事務,就以非事務方式執行。框架

PROPAGATION_MANDATORY(須要事務)ide

使用當前的事務,若是當前沒有事務,就拋出異常。工具

PROPAGATION_REQUIRES_NEW(獨立事務)測試

新建事務,若是當前存在事務,把當前事務掛起。url

PROPAGATION_NOT_SUPPORTED(非事務方式)spa

以非事務方式執行操做,若是當前存在事務,就把當前事務掛起。

PROPAGATION_NEVER(排除事務)

以非事務方式執行,若是當前存在事務,則拋出異常。

PROPAGATION_NESTED(嵌套事務)

若是當前存在事務,則在嵌套事務內執行。若是當前沒有事務,則執行與PROPAGATION_REQUIRED相似的操做。


        Spring默認的事務傳播行爲是PROPAGATION_REQUIRED,它適合於絕大多數的狀況。假設ServiveX#methodX()都工做在事務環境下(即都被Spring事務加強了),假設程序中存在以下的調用鏈:Service1#method1()->Service2#method2()->Service3#method3(),那麼這3個服務類的3個方法經過Spring的事務傳播機制都工做在同一個事務中。

        若是在一個ServiceA和a()方法中啓動一個線程,在這個新建立的線程中執行ServiceB的事務方法b()。在相同線程中進行相互嵌套調用的事務方法工做於相同的事務中。若是這些相互嵌套調用的方法工做在不一樣的線程中,不一樣線程下的事務方法工做在獨立的事務中。


2多種數據持久方法事務管理

        若是你採用了一個高端ORM技術(Hibernate,JPA,JDO),同時採用一個JDBC技術(Spring JDBC,iBatis),因爲前者的會話(Session)是對後者鏈接(Connection)的封裝,Spring會「足夠智能地」在同一個事務線程讓前者的會話封裝後者的鏈接。因此,咱們只要直接採用前者的事務管理器就能夠了。下表給出了混合數據訪問技術所對應的事務管理器: 

1不一樣持久方式的事務統一

     Spring提供了一個能從當前事務上下文中獲取綁定的數據鏈接的工具類,那就是DataSourceUtils。Spring強調必須使用DataSourceUtils工具類獲取數據鏈接。

 static Connection doGetConnection(DataSource dataSource)

首先嚐試從事務上下文中獲取鏈接,失敗後再從數據源獲取鏈接;

static Connection getConnection(DataSource dataSource)

doGetConnection方法的功能同樣,實際上,它內部就是調用doGetConnection方法獲取鏈接的;

static void  doReleaseConnection(Connection con, DataSource dataSource)

釋放鏈接,放回到鏈接池中;

static void release Connection(Connection con, DataSource dataSource)

和doReleaseConnection方法的功能同樣,實際上,它內部就是調用doReleaseConnection方法獲取鏈接的;

測試demo:

@Service
public class TestTranscationServiceImpl implements TestTranscationService {

    @Autowired
    private TestTranscationDao testTranscationDao;

    @Override
    @Transactional
    public int test(){
        testTranscationDao.update1();
        testTranscationDao.update2();       
        return 0;
    }
}
@Autowired
    private JdbcTemplate jdbcTemplate;

    @Override
    public int update1() {
        //1.得到數據庫鏈接
        Connection con = DataSourceUtils.getConnection(jdbcTemplate.getDataSource());
        try {
            con.prepareStatement("update grade_info set grade_name='11' where grade_id=1").executeUpdate();
        } catch (SQLException e) {
            throw new RuntimeException(e);
        }finally {
            //2若是當前方法沒有上下文事務管理,不釋放數據庫鏈接會形成數據庫鏈接泄露
            //若是存在上下文事務,調用或者不調用數據庫鏈接釋放都沒有問題
            DataSourceUtils.releaseConnection(con, jdbcTemplate.getDataSource());
        }
        return 0;

    }

    @Override
    public int update2(){
        //3.得到數據庫鏈接   和1的數據庫鏈接是同一個鏈接
        Connection con = DataSourceUtils.getConnection(jdbcTemplate.getDataSource());
        try {
            //4.這種方法取到的數據庫鏈接和 1,3取到的數據庫鏈接不一樣
            Connection conn = jdbcTemplate.getDataSource().getConnection();
            conn.close();
        } catch (SQLException e) {
            e.printStackTrace();
        }
        return jdbcTemplate.update("update grade_info set grade_name='高中三年級' where grade_id=1");
    }

        Spring爲每一個數據訪問技術框架都提供了一個獲取事務上下文綁定的數據鏈接(或其衍生品)的工具類和數據源(或其衍生品)的代理類。 


2Hibernate和JDBC混合使用注意事項

        因爲Hibernate一級緩存的緣由,在經過save,update,delete等方法操做數據時,並無真正向數據庫發送SQL,只有調用flush()時,Hibernate纔會將一級緩存中的狀態變化同步到數據庫中。

        Hibernate的事務管理在提交事務時,會自動調用flush()操做,將一級緩存同步到數據庫中,此時纔會將產生並向數據庫發送SQL語句。

        正是由於以上緣由的存在,全部在混合使用JDBC和Hibernate時,可能存在丟失更新的問題。

        在混合使用Hibernate和JDBC時,JDBC的操做不會同步到Hibernate的緩存中(一級緩存及二級緩存),Hibernate緩存中的狀態變動也不被JDBC感知。所以混合使用時必須特別關注這一點。

        因爲混合數據訪問技術的方案的事務同步而緩存不一樣步的狀況,因此最好用Hibernate完成讀寫操做,而用Spring JDBC完成讀的操做。如用Spring JDBC進行簡要列表的查詢,而用Hibernate對查詢出的數據進行維護。若是確實要同時使用Hibernate和Spring JDBC讀寫數據,則必須充分考慮到Hibernate緩存機制引起的問題:必須充分分析數據維護邏輯,根據須要,及時調用Hibernate的flush()方法,以避免覆蓋Spring JDBC的更改,在Spring JDBC更改數據庫時,維護Hibernate的緩存。

3Spring的事務加強限制條件

        因爲Spring事務管理是基於接口代理或動態字節碼技術,經過AOP實施事務加強的。

        對於基於接口動態代理的AOP事務加強來講,因爲接口的方法是public的,這就要求實現類的實現方法必須是public的(不能是protected,private等),同時不能使用static的修飾符。因此,能夠實施接口動態代理的方法只能是使用「public」或「public final」修飾符的方法,其它方法不可能被動態代理,相應的也就不能實施AOP加強,也即不能進行Spring事務加強了。

        基於CGLib字節碼動態代理的方案是經過擴展被加強類,動態建立子類的方式進行AOP加強植入的。因爲使用final,static,private修飾符的方法都不能被子類覆蓋,相應的,這些方法將不能被實施的AOP加強。因此,必須特別注意這些修飾符的使用,以避免不當心成爲事務管理的漏網之魚。

4Spring事務管理的異常捕捉,事務回滾

        spring的事務管理器只對 unchecked exception進行異常回滾,Error和RuntimeException及其子類是unchecked exception.其餘exception是checked exception.  

        若是在service層中,使用了try ,catch來捕捉異常,致使sevice層出現的異常被 「截留」,沒法拋出給事務管理器,這就給事務管理器形成一種假象,就像程序在運行中,沒有產生任何問題,所以也就不會對出現 runtimeException進行回滾操做。


文章來自於網上資源整理,本身通過demo測試

友情連接:

Spring 3.x企業實用開發實戰》做者博客http://stamen.iteye.com/category/209694有相關係列博文

百度文庫PPT: Spring高級事務管理難點難點剖析

相關文章
相關標籤/搜索