首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> Java 程式設計 >> Java 相關知識

Spring 事務管理深度實戰:編程式與聲明式事務完整對比與最佳實踐

     編輯:Java 相關知識

事務四大特性 (ACID)

特性說明
原子性事務內操作要麼全成功,要麼全失敗回滾
一致性資料庫從一個一致狀態轉移到另一個一致狀態
隔離性並發事務間互不干擾,通過隔離級別控制
持久性提交後的修改永久生效,不因系統故障丟失

Spring 事務管理兩大範式

  • 編程式事務:代碼中顯式控制提交/回滾,靈活但侵入性強,維護成本高。
  • 聲明式事務:基於 AOP,通過註解或 XML 配置切面,業務代碼零侵入,推薦生產環境使用。

本地事務 vs 全局事務

  • 本地事務:單一資源(如單 DataSource),輕量,Spring DataSourceTransactionManager 管理。
  • 全局事務:跨多資源(多庫、JMS 等),需 JTA 管理器(JtaTransactionManager)與應用服務器協同。

編程式事務完整實現

public class StudentJDBCTemplate implements StudentDAO {
    private PlatformTransactionManager txManager;
    private JdbcTemplate jdbcTemplate;

    public void setTransactionManager(PlatformTransactionManager txManager) {
        this.txManager = txManager;
    }

    @Override
    public void create(String name, Integer age, Integer marks, Integer year) {
        TransactionDefinition def = new DefaultTransactionDefinition();
        TransactionStatus status = txManager.getTransaction(def);
        try {
            jdbcTemplate.update("INSERT INTO Student(name,age) VALUES(?,?)", name, age);
            Integer sid = jdbcTemplate.queryForObject("SELECT MAX(id) FROM Student", Integer.class);
            jdbcTemplate.update("INSERT INTO Marks(sid,marks,year) VALUES(?,?,?)", sid, marks, year);
            txManager.commit(status);
        } catch (DataAccessException e) {
            txManager.rollback(status);
            throw e;
        }
    }
    // listStudents 省略
}
<!-- XML 配置事務管理器 -->
<bean id="txManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
    <property name="dataSource" ref="dataSource"/>
</bean>

聲明式事務:註解驅動(現代首選)

<!-- 啟用註解事務 -->
<tx:annotation-driven transaction-manager="txManager"/>
@Service
public class StudentServiceImpl implements StudentService {
    @Autowired StudentDAO studentDAO;

    @Transactional(rollbackFor = Exception.class) // 預設僅回滾 RuntimeException
    public void createStudent(String name, Integer age, Integer marks, Integer year) {
        studentDAO.create(name, age, marks, year);
        // 模擬業務異常觸發回滾
        if ("error".equals(name)) throw new RuntimeException("模擬異常");
    }
}

聲明式事務:XML 配置式(傳統專案維護)

<tx:advice id="txAdvice" transaction-manager="txManager">
    <tx:attributes>
        <tx:method name="create*" rollback-for="java.lang.Exception"/>
        <tx:method name="*"/> <!-- 其他方法預設只讀 -->
    </tx:attributes>
</tx:advice>

<aop:config>
    <aop:pointcut id="serviceOps" expression="execution(* com.example.service.*.*(..))"/>
    <aop:advisor advice-ref="txAdvice" pointcut-ref="serviceOps"/>
</aop:config>

事務屬性核心配置

屬性說明常用值
propagation傳播行為REQUIRED(預設)、REQUIRES_NEW、NESTED
isolation隔離級別READ_COMMITTED(預設)、REPEATABLE_READ、SERIALIZABLE
timeout超時秒數-1 表示無超時
readOnly只讀優化true/false
rollbackFor觸發回滾的異常Exception.class(建議顯式指定)

常見坑點與避雷指南

  1. 內部方法調用失效:同類內 this.method() 繞過代理,需注入自身或拆分類。
  2. 異常被吞噬:try-catch 未重拋異常導致事務不回滾。
  3. 非 public 方法:@Transactional 僅對 public 方法生效(protected/private 需 AspectJ)。
  4. 資料源未配置事務管理器:多 DataSource 時需指定 @Transactional("txManagerName")。

總結建議

  • 優先使用 @Transactional 註解,配合 rollbackFor = Exception.class。
  • 合理設計傳播行為,避免巢狀事務不可控。
  • 讀多寫少場景開啟 readOnly=true 讓數據庫優化鎖策略。
  • 長事務拆分為短事務,減少鎖持有時間,提升並發吞吐。
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved