在事务外自动保存托管JPA实体
Spring中的存儲(chǔ)庫和事務(wù)并存。 Spring中的所有數(shù)據(jù)庫訪問都應(yīng)在事務(wù)內(nèi)運(yùn)行,并且通常在某個(gè)地方使用@Transactional來強(qiáng)制執(zhí)行此操作。 但是,這并非總是必要的。 例如,當(dāng)使用Spring Data時(shí),您的存儲(chǔ)庫使用SimpleJPARepository來實(shí)現(xiàn)CRUD功能。 SimpleJPARepository使用@Transactional因此在執(zhí)行CRUD操作時(shí),已經(jīng)為您處理了事務(wù)。 這可能會(huì)給人以錯(cuò)誤的印象,即您不需要使用@Transactional注釋自己的類,因?yàn)閮H當(dāng)您知道自己在做什么時(shí),這才是正確的。
考慮以下基于Spring Data的時(shí)間序列示例來管理汽車租賃:
public CarRentalEntry createNewRental(Car car) {CarRentalEntry latestEntry = carRentalRepository.findByCarId(car.getId());latestCarRentalEntry.setEndDate(LocalDate.now());CarRentalEntry newEntry = new CarRentalEntry();newEntry.setCarId(car.getId())newEntry.setStartDate(LocalDate.now());newEntry.setEndDate(null);carRentalRepository.save(newEntry); }在上面的示例中,通過存儲(chǔ)庫獲取了特定汽車的最新租車條目,并結(jié)束了該租車條目。 然后,將創(chuàng)建并保存一個(gè)新的汽車租賃條目。 由于carRentalRepository是一個(gè)處理事務(wù)的SimpleJPARepository ,因此無需@Transactional carRentalRepository可以使用。 現(xiàn)在考慮在更改latestEntry的結(jié)束日期之前進(jìn)行保存的以下latestEntry :
public CarRentalEntry createNewRental(Car car) { CarRentalEntry newEntry = new CarRentalEntry();newEntry.setCarId(car.getId())newEntry.setStartDate(LocalDate.now());newEntry.setEndDate(null);carRentalRepository.save(newEntry);CarRentalEntry latestEntry = carRentalRepository.findByCarId(car.getId());latestCarRentalEntry.setEndDate(LocalDate.now());}從功能上講,該方法完全相同,但是在此示例中,將僅執(zhí)行保存 。 因?yàn)闆]有事務(wù),對(duì)latestEntry修改將不會(huì)保存到數(shù)據(jù)庫中! 為了使這種方法有效,必須使用@Transactional注釋createNewRental() 。 如果JPA受管實(shí)體上的任何更改發(fā)生在正常JPA行為的事務(wù)內(nèi),則僅將其自動(dòng)保存。 因此,問題在于為什么第一種方法不需要交易。
實(shí)際上確實(shí)如此。 當(dāng)latestEntry是通過存儲(chǔ)庫讀取,它被加入到persistanceContext JPAS的(又名1級(jí)高速緩存) entityManager 。 當(dāng)調(diào)用save()方法時(shí),它在事務(wù)提交時(shí)刷新了persistanceContext ,這反過來又帶來了副作用,即還保留了修改后的latestEntry 。 在第二個(gè)示例中, persistanceContext latestEntry在調(diào)用save()時(shí)沒有l(wèi)atestEntry 。 因?yàn)樵诜椒ㄍ瓿蓵r(shí)沒有事務(wù)提交,所以不會(huì)刷新更改。 通過添加@Transactional ,再次刷新persistanceContext ,并將修改內(nèi)容寫入數(shù)據(jù)庫。 請(qǐng)注意,第二個(gè)示例也可以通過調(diào)用carRentalRepository.flush() @Transactional ,因?yàn)樗部梢栽?#64;Transactional下運(yùn)行。
最重要的是,您應(yīng)該控制自己的事務(wù),因?yàn)檫@種情況表明容易出錯(cuò)。
最后是調(diào)試Hibernate和受管實(shí)體問題時(shí)的提示。 放置斷點(diǎn)的良好候選類是:
- org.springframework.orm.jpa.JpaTransactionManager
- org.hibernate.jpa.internal.TransactionImpl.commit()要刷新的持久性上下文通常在TransactionImpl.entityManager.session.persistenceContext找到
翻譯自: https://www.javacodegeeks.com/2018/05/automatic-save-of-managed-jpa-entities-outside-of-transaction.html
總結(jié)
以上是生活随笔為你收集整理的在事务外自动保存托管JPA实体的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 离郑备案表(离郑备案)
- 下一篇: (翻墙手机安卓)