Spring常見的事務(wù)失效場景及解決方案
常見失效場景
1.方法不是 public
Spring AOP 代理默認(rèn)只對 public 方法生效。如果被 @Transactional 注解的方法不是 public 的,事務(wù)將不會生效。
示例代碼
@Service
public class UserService {
@Transactional
protected void updateUser(User user) {
// 更新用戶信息
}
}
解決方案: 將方法改為 public。
@Service
public class UserService {
@Transactional
public void updateUser(User user) {
// 更新用戶信息
}
}
2.自我調(diào)用問題
當(dāng)一個(gè)類中的方法調(diào)用同一個(gè)類中的另一個(gè) @Transactional 方法時(shí),事務(wù)不會傳播到被調(diào)用的方法。
示例代碼:
@Service
public class UserService {
@Transactional
public void updateUser(User user) {
internalUpdate(user);
}
@Transactional
private void internalUpdate(User user) {
// 更新用戶信息
}
}
解決方案: 使用 AopContext.currentProxy() 或者通過 @Autowired 注入當(dāng)前類的代理對
@Service
public class UserService {
@Autowired
private UserService userService;
@Transactional
public void updateUser(User user) {
userService.internalUpdate(user);
}
@Transactional
private void internalUpdate(User user) {
// 更新用戶信息
}
}
3.異常被捕獲
如果在事務(wù)方法中捕獲了異常并且沒有重新拋出,Spring 框架無法檢測到異常,從而不會回滾事務(wù)。
示例代碼:
@Service
public class UserService {
@Transactional
public void updateUser(User user) {
try {
// 更新用戶信息
} catch (Exception e) {
// 異常被捕獲,事務(wù)不會回滾
}
}
}
解決方案: 捕獲異常后重新拋出,或者使用 TransactionAspectSupport.currentTransactionStatus().setRollbackOnly()。
@Service
public class UserService {
@Transactional
public void updateUser(User user) {
try {
// 更新用戶信息
} catch (Exception e) {
TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
}
}
}
4.配置錯(cuò)誤
事務(wù)管理器配置錯(cuò)誤或未正確配置,例如 @EnableTransactionManagement 缺失或事務(wù)管理器 bean 名稱不匹配。
示例代碼:
@Configuration
public class AppConfig {
@Bean
public PlatformTransactionManager transactionManager() {
return new DataSourceTransactionManager(dataSource());
}
@Bean
public DataSource dataSource() {
// 配置數(shù)據(jù)源
}
}
解決方案: 確保 @EnableTransactionManagement 注解存在,并且事務(wù)管理器配置正確。
@Configuration
@EnableTransactionManagement
public class AppConfig {
@Bean
public PlatformTransactionManager transactionManager() {
return new DataSourceTransactionManager(dataSource());
}
@Bean
public DataSource dataSource() {
// 配置數(shù)據(jù)源
}
}
5.事務(wù)傳播行為
不正確的事務(wù)傳播行為設(shè)置可能導(dǎo)致事務(wù)不按預(yù)期工作。例如,使用 REQUIRES_NEW 傳播行為時(shí),新的事務(wù)會被創(chuàng)建,但原來的事務(wù)可能不會回滾。
示例代碼
@Service
public class UserService {
@Transactional(propagation = Propagation.REQUIRES_NEW)
public void updateUser(User user) {
// 更新用戶信息
}
}
解決方案: 根據(jù)業(yè)務(wù)需求選擇合適的事務(wù)傳播行為。
@Service
public class UserService {
@Transactional(propagation = Propagation.REQUIRED)
public void updateUser(User user) {
// 更新用戶信息
}
}
6.事務(wù)隔離級別
不合適的事務(wù)隔離級別可能導(dǎo)致數(shù)據(jù)一致性問題,例如臟讀、不可重復(fù)讀和幻讀。
示例代碼
@Service
public class UserService {
@Transactional(isolation = Isolation.READ_UNCOMMITTED)
public void updateUser(User user) {
// 更新用戶信息
}
}
解決方案: 根據(jù)業(yè)務(wù)需求選擇合適的事務(wù)隔離級別。
@Service
public class UserService {
@Transactional(isolation = Isolation.READ_COMMITTED)
public void updateUser(User user) {
// 更新用戶信息
}
}
7.事務(wù)超時(shí)
事務(wù)超時(shí)設(shè)置不合理,導(dǎo)致事務(wù)在執(zhí)行過程中被自動回滾。
示例代碼:
@Service
public class UserService {
@Transactional(timeout = 1) // 超時(shí)時(shí)間設(shè)置為1秒
public void updateUser(User user) {
// 更新用戶信息
}
}
解決方案: 根據(jù)業(yè)務(wù)需求設(shè)置合理的事務(wù)超時(shí)時(shí)間。
@Service
public class UserService {
@Transactional(timeout = 60) // 超時(shí)時(shí)間設(shè)置為60秒
public void updateUser(User user) {
// 更新用戶信息
}
}
8.只讀事務(wù)
如果事務(wù)被標(biāo)記為只讀(readOnly=true),則不能進(jìn)行任何修改操作,否則會拋出異常。
示例代碼:
@Service
public class UserService {
@Transactional(readOnly = true)
public User getUserById(Long id) {
// 查詢用戶信息
}
}
解決方案: 確保只讀事務(wù)中不進(jìn)行任何修改操作。
@Service
public class UserService {
@Transactional(readOnly = false)
public void updateUser(User user) {
// 更新用戶信息
}
}
9.數(shù)據(jù)庫連接問題
數(shù)據(jù)庫連接池配置不當(dāng)或數(shù)據(jù)庫連接斷開,導(dǎo)致事務(wù)無法正常提交或回滾。
示例代碼:
@Configuration
public class AppConfig {
@Bean
public DataSource dataSource() {
HikariConfig config = new HikariConfig();
config.setJdbcUrl("jdbc:mysql://localhost:3306/test");
config.setUsername("root");
config.setPassword("password");
return new HikariDataSource(config);
}
}
解決方案: 確保數(shù)據(jù)庫連接池配置正確,并且數(shù)據(jù)庫連接穩(wěn)定。
@Configuration
public class AppConfig {
@Bean
public DataSource dataSource() {
HikariConfig config = new HikariConfig();
config.setJdbcUrl("jdbc:mysql://localhost:3306/test");
config.setUsername("root");
config.setPassword("password");
config.setMaximumPoolSize(10); // 設(shè)置最大連接數(shù)
return new HikariDataSource(config);
}
}
10.事務(wù)管理器不匹配
使用了錯(cuò)誤的事務(wù)管理器,例如在使用 JPA 時(shí)配置了 JDBC 事務(wù)管理器,或者在使用 MyBatis 時(shí)配置了 Hibernate 事務(wù)管理器。
示例代碼:
@Configuration
public class AppConfig {
@Bean
public PlatformTransactionManager transactionManager(EntityManagerFactory emf) {
return new JpaTransactionManager(emf);
}
}
解決方案: 根據(jù)使用的持久層框架選擇合適的事務(wù)管理器。
@Configuration
public class AppConfig {
@Bean
public PlatformTransactionManager transactionManager(DataSource dataSource) {
return new DataSourceTransactionManager(dataSource);
}
}
總結(jié)
Spring 事務(wù)管理雖然強(qiáng)大,但在實(shí)際開發(fā)中需要注意許多細(xì)節(jié)。本文列舉了十種常見的事務(wù)失效情況,并提供了相應(yīng)的解決方案和示例代碼。希望這些內(nèi)容能幫助開發(fā)者更好地理解和使用 Spring 事務(wù)管理,確保數(shù)據(jù)的一致性和完整性。
以上就是Spring常見的事務(wù)失效場景及解決方案的詳細(xì)內(nèi)容,更多關(guān)于Spring事務(wù)失效場景及解決的資料請關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
關(guān)于QueryWrapper,實(shí)現(xiàn)MybatisPlus多表關(guān)聯(lián)查詢方式
這篇文章主要介紹了關(guān)于QueryWrapper,實(shí)現(xiàn)MybatisPlus多表關(guān)聯(lián)查詢方式,具有很好的參考價(jià)值,希望對大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教。2022-01-01
mybatis如何使用Criteria的and和or進(jìn)行聯(lián)合查詢
這篇文章主要介紹了mybatis如何使用Criteria的and和or進(jìn)行聯(lián)合查詢,具有很好的參考價(jià)值,希望對大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2021-12-12
java控制臺實(shí)現(xiàn)學(xué)生信息管理系統(tǒng)(集合版)
這篇文章主要為大家詳細(xì)介紹了java控制臺實(shí)現(xiàn)學(xué)生信息管理系統(tǒng)的集合版,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2021-04-04
使用 Spring Boot 實(shí)現(xiàn) WebSocket實(shí)時(shí)通信
本篇文章主要介紹了使用 Spring Boot 實(shí)現(xiàn) WebSocket實(shí)時(shí)通信,小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過來看看吧2017-10-10

