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

Java 事務管理模式演進:從硬編碼到聲明式 AOP 的最佳實踐

     編輯:Java 相關知識

場景痛點:Service 層事務代碼為何難維護?

傳統做法在 Service 方法中硬編碼事務控制:

public boolean buyBook(String bookId, int qty) {
    Connection conn = ConnectionManager.getConnection();
    try {
        conn.setAutoCommit(false);
        BookDAO dao = DAOFactory.getBookDAO();
        if (dao.reduceInventory(conn, bookId, qty)) {
            CustomerDAO cdao = DAOFactory.getCustomerDAO();
            cdao.reduceAccount(conn, price);
            // ... 其他業務
            conn.commit();
        }
    } catch (SQLException e) {
        conn.rollback();
        throw new SystemException(e);
    } finally {
        conn.setAutoCommit(true);
    }
}

三大弊端:

  1. 代碼重複:每個方法複製粘貼事務模板
  2. 職責混雜:業務邏輯耦合事務基礎設施
  3. 嵌套事務無解:Service 互調形成嵌套事務,無法統一控制

優雅解決:動態代理 + Transaction Wrapper

利用 JDK 動態代理(針對接口)將事務控制剝離:

1. 事務攔截器

public final class TransactionWrapper {
    public static Object decorate(Object delegate) {
        return Proxy.newProxyInstance(
            delegate.getClass().getClassLoader(),
            delegate.getClass().getInterfaces(),
            new TxInvocationHandler(delegate)
        );
    }

    static class TxInvocationHandler implements InvocationHandler {
        private final Object delegate;
        TxInvocationHandler(Object delegate) { this.delegate = delegate; }

        @Override
        public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
            Connection con = ConnectionManager.getConnection();
            try {
                con.setAutoCommit(false);  // 開啟事務
                Object result = method.invoke(delegate, args);  // 調用業務方法
                con.commit();              // 提交
                con.setAutoCommit(true);
                return result;
            } catch (Throwable t) {
                con.rollback();            // 回滾
                con.setAutoCommit(true);
                throw new SystemException(t);
            }
        }
    }
}

2. 純淨的 Service 實現

public class BookStoreManagerImpl implements BookStoreManager {
    public boolean buyBook(String bookId, int qty) throws SystemException {
        Connection conn = ConnectionManager.getConnection();
        BookDAO bookDAO = DAOFactory.getBookDAO();
        CustomerDAO customerDAO = DAOFactory.getCustomerDAO();
        if (bookDAO.reduceInventory(conn, bookId, qty)) {
            BigDecimal price = bookDAO.getPrice(bookId);
            return customerDAO.reduceAccount(conn, price.multiply(new BigDecimal(qty)));
        }
        return false;
    }
}

3. 工廠提供雙模式獲取

public final class ManagerFactory {
    // 帶事務代理版
    public static BookStoreManager getBookStoreManagerTrans() {
        return (BookStoreManager) TransactionWrapper.decorate(new BookStoreManagerImpl());
    }
    // 純業務版(用於嵌套調用,加入外層事務)
    public static BookStoreManager getBookStoreManager() {
        return new BookStoreManagerImpl();
    }
}

進階:聲明式事務配置化

硬編碼「所有方法開啟事務」不夠靈活。引入 XML 配置指定哪些方法需要事務:

<tx:advice id="txAdvice" transaction-manager="txManager">
    <tx:attributes>
        <tx:method name="buy*" propagation="REQUIRED" rollback-for="SystemException"/>
        <tx:method name="query*" propagation="SUPPORTS" read-only="true"/>
        <tx:method name="*" propagation="REQUIRED"/>
    </tx:attributes>
</tx:advice>

AOP 實現方式對比

技術原理優點局限
JDK 動態代理接口代理,反射調用標準 API,無依賴只能代理接口
CGLIB字節碼生成子類可代理類、無接口不能代理 final 方法/類
AspectJ (CTW/LTW)編譯期/類加載期織入功能最全,無運行時開銷構建複雜,學習曲線陡

Spring 默認:有接口用 JDK,無接口用 CGLIB。

嵌套事務解決方案:傳播行為

  • REQUIRED(默認):有事務加入,無則新建
  • REQUIRES_NEW:掛起當前,新建獨立事務
  • NESTED:JDBC 3.0 Savepoint,子事務可獨立回滾
  • SUPPORTS:有事務加入,無則非事務運行

工廠雙模式本質是手動控制傳播:getBookStoreManagerTrans() = REQUIRED,getBookStoreManager() = SUPPORTS/MANDATORY。

總結

從硬編碼 → 動態代理 → 聲明式 AOP,是事務管理架構演進的必經之路。核心思想:事務是橫切關注點,應與業務邏輯分離。Spring @Transactional 註解是這一思想的工業級實踐。理解底層原理(代理、攔截器鏈、傳播行為),能幫你在複雜場景(分布式事務、嵌套回滾、只讀優化)做出正確架構決策。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved