Spring 事務詳解
一、Spring 事務簡介
Spring 事務管理基于?AOP(面向切面編程)實現,通過?聲明式事務(注解或 XML 配置)統一管理數據庫操作,確保數據一致性。核心目標:保證多個數據庫操作的原子性(要么全部成功,要么全部回滾)。
核心優勢:
-
解耦業務代碼與事務管理:通過注解配置,無需侵入業務邏輯。
-
支持多種事務管理器:如 JDBC、Hibernate、JPA 等。
-
靈活的事務傳播行為:控制事務的邊界和嵌套邏輯。
二、?案例:銀行賬戶轉賬
需求:用戶 A 向用戶 B 轉賬,需保證扣款和存款操作同時成功或失敗。
代碼實現
(1) 業務層接口與實現類
public interface AccountService {void transfer(String fromUser, String toUser, int money);
}@Service
public class AccountServiceImpl implements AccountService {@Autowiredprivate AccountDao accountDao;@Transactional // 開啟事務管理@Overridepublic void transfer(String fromUser, String toUser, int money) {// 扣款accountDao.reduceMoney(fromUser, money);// 模擬異常(事務應回滾)// int i = 1 / 0; // 存款accountDao.addMoney(toUser, money);}
}
(2) 數據層(DAO)
@Repository
public class AccountDaoImpl implements AccountDao {@Autowiredprivate JdbcTemplate jdbcTemplate;public void reduceMoney(String user, int money) {String sql = "UPDATE account SET balance = balance - ? WHERE username = ?";jdbcTemplate.update(sql, money, user);}public void addMoney(String user, int money) {String sql = "UPDATE account SET balance = balance + ? WHERE username = ?";jdbcTemplate.update(sql, money, user);}
}
三、Spring 事務核心配置
步驟 1:啟用事務管理
-
Spring Boot:默認已啟用事務,無需額外配置。
-
非 Spring Boot:在配置類添加?
@EnableTransactionManagement
。@Configuration @EnableTransactionManagement // 開啟注解式事務驅動 public class AppConfig { ... }
步驟 2:配置事務管理器
-
Spring Boot:自動配置?
DataSourceTransactionManager
。 -
手動配置:
@Bean public PlatformTransactionManager transactionManager(DataSource dataSource) {return new DataSourceTransactionManager(dataSource); }
步驟 3:使用?@Transactional
?注解
-
作用位置:類(所有方法生效)或方法。
-
關鍵屬性:
-
propagation
:事務傳播行為(默認?REQUIRED
)。 -
isolation
:事務隔離級別(默認?DEFAULT
,跟隨數據庫)。 -
rollbackFor
:指定觸發回滾的異常類型。 -
timeout
:事務超時時間(秒)。
-
四、Spring 事務角色
角色 | 說明 |
---|---|
事務管理器 | PlatformTransactionManager ?接口的實現類(如?DataSourceTransactionManager )。 |
事務定義 | 通過?@Transactional ?注解或 XML 配置定義事務屬性(傳播行為、隔離級別等)。 |
事務狀態 | 事務的運行時狀態(如是否是新事務、是否回滾)。 |
五、Spring 事務屬性
屬性 | 說明 | 常用值 |
---|---|---|
propagation | 事務傳播行為(控制事務邊界) | REQUIRED (默認)、REQUIRES_NEW 、NESTED 、SUPPORTS ?等。 |
isolation | 事務隔離級別(解決并發問題) | DEFAULT 、READ_COMMITTED 、READ_UNCOMMITTED 、REPEATABLE_READ ?等。 |
timeout | 事務超時時間(秒),超時自動回滾。 | 默認 -1(無超時)。 |
readOnly | 是否只讀事務(優化數據庫性能)。 | true ?或?false (默認)。 |
rollbackFor | 觸發回滾的異常類型(默認僅回滾?RuntimeException )。 | 如?rollbackFor = Exception.class 。 |
noRollbackFor | 不觸發回滾的異常類型。 | 如?noRollbackFor = NullPointerException.class 。 |
六、 事務傳播行為(Propagation)
控制事務方法之間如何相互影響,常見行為:
傳播行為 | 說明 |
---|---|
REQUIRED | 如果當前存在事務,則加入該事務;否則新建一個事務(默認行為)。 |
REQUIRES_NEW | 無論當前是否存在事務,都新建一個事務,掛起當前事務(獨立提交)。 |
SUPPORTS | 如果當前存在事務,則加入;否則以非事務方式執行。 |
NESTED | 如果當前存在事務,則嵌套在子事務中執行(可部分回滾)。 |
七、案例:轉賬業務追加日志
需求:在轉賬操作后記錄日志,且日志記錄必須成功(即使轉賬失敗也要記錄)。
代碼實現
@Service
public class LogService {@Autowiredprivate LogDao logDao;// 使用 REQUIRES_NEW 傳播行為:獨立事務@Transactional(propagation = Propagation.REQUIRES_NEW)public void addLog(String logInfo) {logDao.insertLog(logInfo);// 即使轉賬失敗,日志也會提交}
}@Service
public class AccountServiceImpl implements AccountService {@Autowiredprivate AccountDao accountDao;@Autowiredprivate LogService logService;@Transactional@Overridepublic void transfer(String fromUser, String toUser, int money) {accountDao.reduceMoney(fromUser, money);accountDao.addMoney(toUser, money);// 記錄日志(獨立事務)logService.addLog("轉賬操作:" + fromUser + " 向 " + toUser + " 轉賬 " + money);}
}
關鍵點:
-
日志方法?
addLog
?使用?REQUIRES_NEW
,確保日志事務獨立提交。 -
即使轉賬事務回滾,日志事務仍會提交。
八、事務配置示例
@Transactional(propagation = Propagation.REQUIRED,isolation = Isolation.READ_COMMITTED,timeout = 30,rollbackFor = {SQLException.class, IOException.class}
)
public void businessMethod() { ... }
九、 常見問題
-
事務不生效:
-
檢查是否啟用事務管理(
@EnableTransactionManagement
)。 -
確保?
@Transactional
?注解應用在?public
?方法上。 -
確認異常類型是否觸發回滾(默認僅回滾?
RuntimeException
?和?Error
)。
-
-
事務傳播行為錯誤:
-
嵌套事務中錯誤使用?
REQUIRES_NEW
?可能導致事務過多,影響性能。
-
十、總結
-
核心注解:
@EnableTransactionManagement
(啟用事務)、@Transactional
(定義事務屬性)。 -
事務傳播行為:根據業務需求選擇合適的行為(如?
REQUIRED
?或?REQUIRES_NEW
)。 -
事務管理本質:基于 AOP 動態代理實現,通過事務管理器控制數據庫連接。
進一步實踐:結合具體業務場景測試不同傳播行為和隔離級別,深入理解事務的邊界控制!