關於Spring架構的 @Transactional工作原理介紹

來源:互聯網
上載者:User

最近做的項目有特別留意到spring的  @Transactional,於是,在網上尋找一番。

本文將深入研究Spring的交易管理。主要介紹@Transactional在底層是如何工作的。之後的文章將介紹: propagation(事務傳播)和isolation(隔離性)等屬性的使用 事務使用的陷阱有哪些以及如何避免 JPA和交易管理

很重要的一點是JPA本身並不提供任何類型的聲明式交易管理。如果在依賴注入容器之外使用JPA,交易處理必須由開發人員編程實現。

1 2 3 4 5 6 7 8 9 10 11 12 UserTransaction utx = entityManager.getTransaction();        try {          utx.begin();            businessLogic();            utx.commit();      } catch (Exception ex) {          utx.rollback();          throw ex;      }

這種方式的交易管理使事務範圍可以在代碼中很清晰地表達出來,但它有以下缺點: 容易出現重複代碼和錯誤 任何錯誤可能產生較大的影響 錯誤難以調試和複現 降低了程式碼程式庫的可讀性 如果該方法調用了其他的事務方法如何處理呢。 使用Spring @Transactional

使用Spring @Transactional,上面的代碼就簡化為:

1 2 3 4 @Transactional      public void businessLogic() {          ... use entity manager inside a transaction ...      }

代碼更加簡潔,可讀性更好,也是目前Spring中交易處理的推薦方式。

通過使用@Transactional,事務傳播等很多重要方面可以自動處理。這種情況下如果businessLogic()調用了其他事務方法,該方法將根據選項確定如何加入正在運行事務。

這個強大機制的一個潛在缺點是它隱藏了底層的運行,當它不能正常工作時很難調試。 @Transactional含義

關於@Transactional,關鍵點之一是要考慮兩個獨立的概念,它們都有各自的範圍和生命週期: persistence context(持久化上下文) database transaction(事務)

@Transactional本身定義了單個事務的範圍。這個事務在persistence context的範圍內。

JPA中的持久化上下文是EntityManager,內部實現使用了Hibernate Session(使用Hibernate作為持久化provider)。

持久化上下文僅僅是一個同步對象,它記錄了有限集合的Java對象的狀態,並且保證這些對象的變化最終持久化到資料庫。

這是與單個事務非常不同的概念。一個Entity Manager可以跨越多個事務使用,而且的確是這樣使用的。 EntityManager何時跨越多個事務。

最常見的情況是應用使用Open Session In View模式處理懶初始化異常時,之前的文章介紹過這種做法的優勢和劣勢。

這種情況下視圖層啟動並執行多個查詢處於獨立的事務中,而不是單事務的商務邏輯,但這些查詢由相同的entity manager管理。

另一種情況是開發人員將持久化上下文標記為PersistenceContextType.EXTENDED,這表示它能夠響應多個請求。 如何定義EntityManager和Transaction之間的關係。

這由應用開發人員來選擇,但是JPA Entity Manager最常用的方式是“Entity Manager per application transaction”(每個事務都有自己的實體管理器)模式。entity manager注入的常用方法是:

1 2 @PersistenceContext      private EntityManager em;

這裡預設為“Entity Manager per transaction”模式。這種模式下如果在@Transactional方法內部使用該Entity Manager,那麼該方法將在單一事務中運行。 @PersistenceContext如何工作。

隨之而來的問題就是@PersistenceContext如何僅在容器啟動時注入entity manager,假定entity manager生命週期很短暫,而且每次請求需要多個entity manager。

答案是它不能:EntityManager是一個介面,注入到spring bean中的不是entity manager本身,而是在運行時代理具體entity manager的context aware proxy(上下文感知代理)。

通常用於代理的具體類為SharedEntityManagerInvocationHandler,藉助調試器可以確認這一點。 那麼@Transactional如何工作。

實現了EntityManager介面的持久化上下文代理並不是聲明式交易管理的唯一部分,事實上包含三個組成部分: EntityManager Proxy本身 事務的切面 交易管理員

看一下這三部分以及它們之間的相互作用。 事務的切面

事務的切面是一個“around(環繞)”切面,在註解的業務方法前後都可以被調用。實現切面的具體類是TransactionInterceptor。

事務的切面有兩個主要職責: 在’before’時,切面提供一個調用點,來決定被調用業務方法應該在進行中事務的範圍內運行,還是開始一個新的獨立事務。 在’after’時,切面需要確定事務被提交,復原或者繼續運行。

在’before’時,事務切面自身不包含任何決策邏輯,是否開始新事務的決策委派給交易管理員完成。 交易管理員

交易管理員需要解決下面兩個問題: 新的Entity Manager是否應該被建立。 是否應該開始新的事務。

這些需要事務切面’before’邏輯被調用時決定。交易管理員的決策基於以下兩點: 事務是否進行中 事務方法的propagation屬性(比如REQUIRES_NEW總要開始新事務)

如果交易管理員確定要建立新事務,那麼將: 建立一個新的entity manager entity manager綁定到當前線程 從資料庫連接池中擷取串連 將串連綁定到當前線程

使用ThreadLocal變數將entity manager和資料庫連接都綁定到當前線程。

事務運行時他們儲存線上程中,當它們不再被使用時,交易管理員決定是否將他們清除。

程式的任何部分如果需要當前的entity manager和資料庫連接都可以從線程中擷取。 EntityManager proxy

EntityManager proxy(前面已經介紹過)就是謎題的最後一部分。當業務方法調用entityManager.persist()時,這不是由entity manager直接調用的。

而是業務方法調用代理,代理從線程擷取當前的entity manager,前面介紹過交易管理員將entity manager綁定到線程。

瞭解了@Transactional機制的各個部分,我們來看一下實現它的常用Spring配置。 整合三個部分

如何將三個部分組合起來使事務註解可以正確地發揮作用呢。首先定義entity manager工廠。

這樣就可以通過持久化上下文註解注入Entity Manager proxy。

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 @Configuration      public class EntityManagerFactoriesConfiguration {          @Autowired          private DataSource dataSource;            @Bean (name = "entityManagerFactory" )          public LocalContainerEntityManagerFactoryBean emf() {              LocalContainerEntityManagerFactoryBean emf = ...              emf.setDataSource(dataSource);              emf.setPackagesToScan(                  new String[] { "your.package" });              emf.setJpaVendorAdapter(                  new HibernateJpaVendorAdapter());              return emf;          }      }

下一步實現配置交易管理員和在@Transactional註解的類中應用事務的切面。

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 @Configuration      @EnableTransactionManagement      public class TransactionManagersConfig {          @Autowired          EntityManagerFactory emf;          @Autowired          private DataSource dataSource;            @Bean (name = "transactionManager" )          public PlatformTransactionManager transactionManager() {              JpaTransactionManager tm =                  new JpaTransactionManager();                  tm.setEntityManagerFactory(emf);                  tm.setDataSource(dataSource);              return tm;          }      }

註解@EnableTransactionManagement通知Spring,@Transactional註解的類被事務的切麵包圍。這樣@Transactional就可以使用了。 總結

Spring聲明式交易管理機制非常強大,但它可能被誤用或者容易發生配置錯誤。

當這個機制不能正常工作或者未達到預期運行結果等問題出現時,理解它的內部工作情況是很有協助的。

需要記住的最重要的一點是,要考慮到兩個概念:事務和持久化上下文,每個都有自己不可讀的明顯的生命週期。

原文連結: javacodegeeks 翻譯: ImportNew.com - hejiani
譯文連結: http://www.importnew.com/12300.html

這是一篇翻譯的文章,挺好的啊,覺得好請頂一下。

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

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.