SpringBoot中的事務管理,用得好,能確保數據的一致性和完整性;用得不好,可能會給性能帶來不小的影響哦。
基本使用
在SpringBoot中,事務的使用非常簡潔。首先,得感謝Spring框架提供的@Transactional
注解,這個小東西可以說是非常強大了。
讓我們先看一個基礎的例子:
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;@Service
public class UserService {@Autowiredprivate UserRepository userRepository;@Transactionalpublic void createUser(String name) {User user = new User(name);userRepository.save(user);// 這里假設有其他的邏輯操作}
}
在這個例子中,我們通過@Transactional
注解標記了createUser
方法。這意味著,當這個方法被調用時,Spring會為我們自動創建一個事務。如果方法正常執行完畢,事務就會提交;如果遇到異常,事務就會回滾,確保數據的一致性。
最近無意間獲得一份阿里大佬寫的刷題筆記,一下子打通了我的任督二脈,進大廠原來沒那么難。
這是大佬寫的,?7701頁的BAT大佬寫的刷題筆記,讓我offer拿到手軟
開啟事務
雖然我們已經看到了如何使用@Transactional
,但是你知道Spring是如何開啟事務的嗎?其實,當我們使用@Transactional
注解時,Spring會通過AOP(面向切面編程)在運行時創建代理對象,來管理事務的開啟和關閉。這個過程對我們來說是透明的,但了解其背后的機制對于深入理解Spring事務是很有幫助的。
事務回滾
默認情況下,如果被@Transactional
注解的方法拋出了運行時異常(RuntimeException
)或者Error
,Spring就會回滾事務。但是,如果你想讓事務在遇到非運行時異常時也回滾,可以這樣做:
@Transactional(rollbackFor = Exception.class)
public void createUserWithRollbackForException(String name) throws Exception {// ...
}
性能優化
事務雖好,但也不是沒有成本的。在某些高并發場景下,過多的事務操作可能會成為性能瓶頸。為了優化性能,我們可以通過以下幾種方式:
- 減少事務范圍:盡量讓事務只包含那些必須要在同一事務中完成的操作。
- 只讀事務:如果事務只涉及到數據的讀取,可以將事務標記為只讀,這樣可以幫助數據庫優化事務處理。
@Transactional(readOnly = true)
public User findUserById(Long id) {return userRepository.findById(id).orElse(null);
}
失效場景
在使用Spring事務的時候,有些情況可能會導致事務失效,比如:
- 自調用問題:在同一個類中,一個非事務方法調用事務方法,事務是不會起作用的。
- 異常處理:如果你在事務方法中捕獲了所有異常,并沒有重新拋出,事務是不會回滾的。
使用場景
事務通常用在需要保證一系列操作要么全部成功,要么全部失敗的場景,比如:
- 用戶注冊時,需要同時創建用戶記錄和用戶的初始數據。
- 訂單支付時,需要更新訂單狀態和用戶的賬戶余額。
代碼示例
讓我們再看一個例子,模擬用戶轉賬的場景:
@Transactional
public void transfer(Long fromId, Long toId, BigDecimal amount) {User fromUser = userRepository.findById(fromId).orElseThrow();User toUser = userRepository.findById(toId).orElseThrow();fromUser.setBalance(fromUser.getBalance().subtract(amount));toUser.setBalance(toUser.getBalance().add(amount));userRepository.save(fromUser);userRepository.save(toUser);
}
在這個例子中,我們通過事務確保了轉賬操作的原子性。如果在轉賬過程中發生任何異常,比如余額不足,整個操作都會回滾,保證賬戶的數據一致性。
SpringBoot中事務管理的一些更高級和具體的應用場景
示例1:聲明式事務的傳播行為
Spring事務的傳播行為定義了事務方法之間的交互方式。舉個例子,我們來看REQUIRED
和REQUIRES_NEW
傳播行為的區別。
@Service
public class AccountService {@Autowiredprivate TransferService transferService;@Transactional(propagation = Propagation.REQUIRED)public void methodA() {// 這里的操作在methodA的事務范圍內transferService.methodB();// 如果methodB出錯,整個methodA都會回滾}@Transactional(propagation = Propagation.REQUIRES_NEW)public void methodB() {// 這里的操作有自己的獨立事務// 即使methodA失敗了,methodB的操作還是會提交}
}
示例2:編程式事務管理
除了聲明式事務,Spring還支持編程式事務管理,這在某些復雜的場景下非常有用。
@Service
public class ComplexService {@Autowiredprivate TransactionTemplate transactionTemplate;public void executeComplexLogic() {transactionTemplate.execute(new TransactionCallback<Void>() {@Overridepublic Void doInTransaction(TransactionStatus status) {// 這里是你的業務邏輯// 如果需要回滾,可以調用 status.setRollbackOnly();return null;}});}
}
示例3:事務的隔離級別
事務的隔離級別決定了一個事務可能受其他并發事務影響的程度。比如,我們來看看如何設置隔離級別:
@Transactional(isolation = Isolation.SERIALIZABLE)
public void transferMoney(Long fromAccountId, Long toAccountId, BigDecimal amount) {// 這個方法會以最高的隔離級別運行,以避免并發事務帶來的問題// 但是性能可能會受影響
}
示例4:事務超時設置
在某些長時間運行的事務中,你可能需要設置事務的超時時間,以避免長時間占用資源。
@Transactional(timeout = 10) // 10秒超時
public void processLargeData() {// 這個方法如果運行超過10秒,事務會被標記為回滾
}
示例5:事務回滾的條件自定義
有時候,你可能需要自定義事務回滾的條件。比如,只在特定的異常出現時才回滾。
@Transactional(rollbackFor = {CustomException.class})
public void updateUserDetails(User user) throws CustomException {// 這個方法只在CustomException拋出時才回滾// 其他異常不會觸發回滾
}
示例6:嵌套事務
嵌套事務允許在一個事務內部開始一個新的事務。如果內部事務失敗,它會回滾到它開始的狀態,而不影響外部事務。
@Transactional
public void parentMethod() {// 父事務的操作...try {nestedMethod();} catch (Exception e) {// 處理內部事務異常,父事務可以繼續}// 父事務的其他操作...
}@Transactional(propagation = Propagation.NESTED)
public void nestedMethod() {// 嵌套事務的操作...
}
示例7:聲明式事務與異常處理
處理聲明式事務時,異常的處理方式至關重要。下面是一個常見的錯誤處理方式。
@Transactional
public void updateUser() {try {// 更新用戶數據的操作...} catch (Exception e) {// 捕獲異常,這將導致事務不回滾}
}
在這個例子中,由于異常被捕獲并沒有重新拋出,事務將不會回滾,這可能會導致數據的不一致性。
示例8:使用事務同步管理器
在某些情況下,你可能需要直接與事務同步管理器進行交互,以獲取當前事務的狀態信息。
public void complexBusinessLogic() {boolean isCurrentTransactionActive = TransactionSynchronizationManager.isActualTransactionActive();if (isCurrentTransactionActive) {// 執行依賴于當前事務的操作...}
}
示例9:異步方法與事務
異步方法和事務一起使用時需要特別小心,因為異步方法通常會在不同的線程中運行,這可能會導致事務管理出現問題。
@Async
@Transactional
public Future<String> asyncMethodWithTransaction() {// 異步操作,但事務可能不會按預期工作// 因為它可能在不同的線程中執行return new AsyncResult<>("Done");
}
示例10:事務日志記錄
在某些業務場景中,你可能需要記錄事務的執行情況,特別是在事務提交或回滾時。
@Transactional
public void transactionalMethodWithLogging() {// 事務操作...TransactionSynchronizationManager.registerSynchronization(new TransactionSynchronizationAdapter() {@Overridepublic void afterCommit() {// 記錄事務提交后的日志}@Overridepublic void afterCompletion(int status) {if (status == TransactionSynchronization.STATUS_ROLLED_BACK) {// 記錄事務回滾的日志}}});
}
通過這些示例,你可以看到Spring事務管理在不同場景下的應用。
理解這些復雜場景對于能夠在實際開發中靈活運用Spring事務管理至關重要。
記住,每個場景都有其特殊性,選擇正確的事務策略可以幫助你避免許多常見的問題。
核心要點
- 基本使用:使用
@Transactional
注解來聲明事務,這是Spring提供的一種聲明式事務管理方式。 - 事務傳播行為:Spring事務的傳播行為定義了事務之間的相互作用,如
REQUIRED
,?REQUIRES_NEW
,?NESTED
等,這決定了事務是否共享或獨立。 - 事務的隔離級別:隔離級別(如
READ_COMMITTED
,?SERIALIZABLE
等)控制事務之間的可見性,防止諸如臟讀、不可重復讀、幻讀等問題。 - 事務的回滾規則:默認情況下,Spring僅在運行時異常發生時回滾事務。可通過
rollbackFor
自定義回滾條件。 - 超時和只讀設置:可以設置事務的超時時間和聲明只讀事務,以優化性能和資源利用。
高級應用場景
- 編程式事務管理:通過
TransactionTemplate
或直接使用PlatformTransactionManager
來手動管理事務。 - 嵌套事務:通過
NESTED
傳播行為實現嵌套事務,內部事務失敗不影響外部事務。 - 異步和事務:異步方法中使用事務需要特別注意,由于執行線程的不同,可能影響事務的管理。
- 事務同步管理:使用
TransactionSynchronizationManager
進行事務的細粒度控制,如在事務提交或回滾后執行特定操作。 - 異常處理與事務回滾:異常處理在事務中非常重要,不當的異常處理可能導致事務不回滾,引起數據不一致。
實際應用建議
- 合理設計事務范圍:避免將大量操作包含在單一事務中,以減少資源鎖定時間和提高性能。
- 注意異常處理:確保適當的異常拋出,以觸發事務回滾。
- 避免在異步方法中使用事務:或者確保你理解如何在多線程環境下正確管理事務。
- 謹慎使用嵌套事務:它們可能會增加復雜性和性能開銷。
- 監控和調優:在生產環境中監控事務的性能,根據需要調整事務策略和配置。
總之,SpringBoot中的事務管理是一個強大但需要謹慎使用的工具。
理解它的工作原理和應用場景,可以幫助你更有效地管理數據一致性和應用性能。
記住,每個應用的需求不同,所以在使用事務時,總是要考慮到你的具體場景和需求。
最后說一句(求關注,求贊,別白嫖我)
最近無意間獲得一份阿里大佬寫的刷題筆記,一下子打通了我的任督二脈,進大廠原來沒那么難。
這是大佬寫的, 7701頁的BAT大佬寫的刷題筆記,讓我offer拿到手軟
項目文檔&視頻:
項目文檔 & 視頻
本文,已收錄于,我的技術網站 ddkk.com,有大廠完整面經,工作技術,架構師成長之路,等經驗分享
求一鍵三連:點贊、分享、收藏
點贊對我真的非常重要!在線求贊,加個關注我會非常感激