日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 前端技术 > javascript >内容正文

javascript

Spring管理的交易说明-第2部分(JPA)

發布時間:2023/12/3 javascript 29 豆豆
生活随笔 收集整理的這篇文章主要介紹了 Spring管理的交易说明-第2部分(JPA) 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

在本系列的第一部分中 ,我展示了事務如何在普通JDBC中工作 。 然后,我展示了Spring如何管理基于JDBC的事務。 在本系列的第二部分中,我將首先展示事務如何在普通的JPA中工作。 然后展示Spring如何管理基于JPA的事務。

資金轉移

為了幫助說明交易,我將使用同一案例研究,將資金從一個銀行帳戶轉移到另一個銀行帳戶。 在這里,我們顯示了借方,貸方和轉賬方法的代碼片段。

... class BankAccountService {public void transfer(MonetaryAmount amount, ...) {debit(amount, ...);credit(amount, ...);...}public void credit(MonetaryAmount amount, AccountId accountId) {...}public void debit(MonetaryAmount amount, AccountId accountId) {...}... }

JPA交易

在普通的JPA中,通過在EntityManager上調用getTransaction().begin()來啟動事務。 下面的代碼段對此進行了說明。

import javax.persistence.*; ... EntityManagerFactory emf = ...; EntityManager em = emf.createEntityManager(); try {em.getTransaction().begin();// make changes through entitiesem.getTransaction().commit();... } catch(Exception e) {em.getTransaction().rollback();throw e; } finally {em.close(); }

從技術上講, EntityManager從創建時就處于事務中。 因此,調用begin()有點多余。 在調用begin()不能調用某些操作,例如persist , merge , remove 。 查詢仍然可以執行(例如find() )。

從查詢返回的對象可以更改。 盡管JPA規范尚不清楚在沒有事務開始時這些更改將發生什么。

現在,讓我們將JPA應用于資金轉移案例研究。

我們定義了一個BankAccount實體來處理debit()和credit()行為。

import javax.persistence.*;@Entity ... class BankAccount {@Id ...;...public void debit(MonetaryAmount amount) {...}public void credit(MonetaryAmount amount) {...}... }

我們將EntityManagerFactory添加到BankAccountService以在需要時啟用EntityManager的創建。

import javax.persistence.*;... class BankAccountService {private EntityManagerFactory emf; // injected via constructor...public void transfer(MonetaryAmount amount, ...) ... {EntityManager em = emf.createEntityManager();try {em.getTransaction().begin();BankAccount fromAccount = em.find(BankAccount.class, ...);BankAccount toAccount = em.find(BankAccount.class, ...);fromAccount.debit(amount);toAccount.credit(amount);em.getTransaction().commit();...} catch(Exception e) {em.getTransaction().rollback();// handle exception (possibly rethrowing it)} finally {em.close();}}public void credit(MonetaryAmount amount, AccountId ...) ... {EntityManager em = emf.createEntityManager();try {em.getTransaction().begin();BankAccount theAccount = em.find(BankAccount.class, ...);theAccount.credit(amount);em.getTransaction().commit();...} catch(Exception e) {em.getTransaction().rollback();// handle exception (possibly rethrowing it)} finally {em.close();}}public void debit(MonetaryAmount amount, AccountId ...) ... {EntityManager em = emf.createEntityManager();try {em.getTransaction().begin();BankAccount theAccount = em.find(BankAccount.class, ...);theAccount.debit(amount);em.getTransaction().commit();...} catch(Exception e) {em.getTransaction().rollback();// handle exception (possibly rethrowing it)} finally {em.close();}} }

Spring管理的JPA交易

transfer , credit和debit方法肯定可以使用模板類(類似于JdbcTemplate )來刪除所有樣板代碼。 Spring以前提供了JpaTemplate類,但是從Spring 3.1開始不推薦使用,而推薦使用本機EntityManager用法(通常通過@PersistenceContext獲得)。

因此,讓我們做到這一點-使用通過@PersistenceContext獲得的EntityManager 。

import javax.persistence.*;... class BankAccountService {@PersistenceContextprivate EntityManager em;...public void transfer(MonetaryAmount amount, ...) ... {try {em.getTransaction().begin();BankAccount fromAccount = em.find(BankAccount.class, ...);BankAccount toAccount = em.find(BankAccount.class, ...);fromAccount.debit(amount);toAccount.credit(amount);em.getTransaction().commit();...} catch(Exception e) {em.getTransaction().rollback();// handle exception (possibly rethrowing it)}}public void credit(MonetaryAmount amount, AccountId ...) ... {try {em.getTransaction().begin();BankAccount theAccount = em.find(BankAccount.class, ...);theAccount.credit(amount);em.getTransaction().commit();...} catch(Exception e) {em.getTransaction().rollback();// handle exception (possibly rethrowing it)}}public void debit(MonetaryAmount amount, AccountId ...) ... {try {em.getTransaction().begin();BankAccount theAccount = em.find(BankAccount.class, ...);theAccount.debit(amount);em.getTransaction().commit();...} catch(Exception e) {em.getTransaction().rollback();// handle exception (possibly rethrowing it)}} }

我們的代碼要簡單一些。 由于我們沒有創建EntityManager ,所以不必關閉它。 但是我們仍在調用getTransaction().begin() 。 有沒有更好的辦法? 首先如何將EntityManager注入對象?

從本系列的前一篇文章中 ,精明的讀者可能已經在考慮讓Spring為我們完成這項工作。 當然是這樣!

EntityManager和@PersistenceContext

我們告訴Spring通過添加PersistenceAnnotationBeanPostProcessor (通過XML <bean>或通過通過AnnotationConfigApplicationContext加載的@Configuration類使用基于Java的配置)從EntityManagerFactory注入EntityManager 。

  • 使用基于XML的配置時, PersistenceAnnotationBeanPostProcessor由<context:annotation-config />元素透明地激活。 并且<context:component-scan />也透明地激活了此元素。
  • 使用基于Java的@Configuration ,將使用AnnotationConfigApplicationContext 。 并使用它始終注冊注釋配置處理器(其中之一是上述PersistenceAnnotationBeanPostProcessor )。

通過添加單個bean定義,Spring容器將充當JPA容器,并從EntityManagerFactory注入EnitityManager 。

JPA和

現在我們有了EntityManager ,如何告訴Spring為我們開始交易?

我們告訴Spring通過將方法標記為@Transactional (或將類標記為@Transactional ,使所有公共方法都具有事務性)來開始事務。 這與Spring通過JDBC啟用事務的方式一致。

import javax.persistence.*; import org.springframework.transaction.annotation.Transactional;@Transactional ... class BankAccountService {@PersistenceContextprivate EntityManager em;...public void transfer(MonetaryAmount amount, ...) ... {BankAccount fromAccount = em.find(BankAccount.class, ...);BankAccount toAccount = em.find(BankAccount.class, ...);fromAccount.debit(amount);toAccount.credit(amount);}public void credit(MonetaryAmount amount, AccountId ...) ... {BankAccount theAccount = em.find(BankAccount.class, ...);theAccount.credit(amount);}public void debit(MonetaryAmount amount, AccountId ...) ... {BankAccount theAccount = em.find(BankAccount.class, ...);theAccount.debit(amount);} }

哇,真好! 我們的代碼短了很多。

就像本系列第一部分中所解釋的那樣,當Spring遇到此注釋時,它將代理該對象(通常稱為Spring管理的Bean)。 代理為標記為@Transactional方法啟動事務(如果沒有正在進行的事務),并在方法成功返回時結束事務。

調用debit()將使用事務。 單獨調用credit()將使用交易。 但是,當調用transfer()時會發生什么?

由于transfer()方法被標記為@Transactional ,Spring將啟動一個事務。 相同的事務將用于對debit()和credit()調用。 換句話說, debit(amount)和credit(amount)不會啟動新交易。 它將使用正在進行的事務(因為有一個事務)。

可是等等! Spring如何知道何時注入適當的實體管理器? 它僅在調用事務方法時才注入嗎?

共享的

在我的一個培訓課程中 ,我嘗試了以下內容,以更好地理解Spring如何通過@PersistenceContext注入EntityManager 。 而且我相信它也會幫助其他人。 因此,這是我嘗試的方法:

import javax.persistence.*; import org.springframework.transaction.annotation.Transactional; import org.springframework.beans.factory.InitializingBean;@Transactional ... class BankAccountService implements InitializingBean {@PersistenceContextprivate EntityManager em;...@Overridepublic void afterPropertiesSet() {System.out.println(em.toString());}... }

應用程序上下文啟動后,控制臺上將顯示類似這樣的輸出。

Shared EntityManager proxy for target factory [...]

那么,這個共享實體管理器是什么?

當應用程序上下文啟動時,Spring注入一個共享實體管理器。 共享EntityManager行為就像從JPA規范定義的從應用程序服務器的JNDI環境中獲取的EntityManager一樣。 它將所有調用委派給當前的事務性EntityManager (如果有); 否則,它將按操作退回到新創建的EntityManager 。

回到我們的問題。 Spring沒有在正確的時間注入正確的實體管理器。 它總是注入一個共享的實體管理器。 但是,該共享實體管理器是事務感知的。 如果存在正在進行的事務,它將委派給當前的事務性EntityManager 。

結論

本系列分為兩部分。 我希望通過從純文本版本的JDBC和JPA(沒有DAO和存儲庫)開始,我可以使自己更清楚地了解Spring如何在后臺管理事務。 而且,通過對Spring的幕后工作有一個更清晰的了解,您可以更好地進行故障排除,了解為什么會得到一個TransactionRequiredException說“沒有可用的事務EntityManager”,并為應用程序添加更好的修復程序。

現在,該冷了。

翻譯自: https://www.javacodegeeks.com/2016/02/spring-managed-transactions-explained-part-2-jpa.html

總結

以上是生活随笔為你收集整理的Spring管理的交易说明-第2部分(JPA)的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。