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

構建線程安全的 Spring Web 應用:從 Servlet 到 Spring 事務管理

     編輯:Java 相關知識

Servlet 容器為每個 Servlet 創建單例,多線程並發訪問同一實例。若 Servlet 使用實例變量保存請求狀態,將導致線程安全災難。本文演進從線程安全基礎到 Spring 聲明式事務的最佳實踐。

線程安全基礎回顧

  • synchronized:互斥但引入阻塞、死鎖風險,性能損耗。
  • 避免同步集合:Hashtable、Vector 方法全同步,優先用 HashMap、ArrayList + 外部同步或並發包。
  • 可重入/無狀態設計:方法僅使用局部變量、參數、ThreadLocal,天然線程安全。

ThreadLocal 模式示例

// 非線程安全:共享實例變量
private Double pi = null;
public Double pi() {
    if (pi == null) pi = new Double(22/7); // 競態條件
    return pi;
}

// 線程安全 + 高性能:ThreadLocal
private static final ThreadLocal pi = new ThreadLocal<>();
public Double pi() {
    if (pi.get() == null) pi.set(new Double(22/7));
    return pi.get();
}

每個線程獨享副本,無競爭、無阻塞。JDK 1.4+ 優化了 ThreadLocal 性能,生產可用。

Web 應用中的線程安全挑戰:數據庫資源

JDBC Connection、Statement、Hibernate Session 均為有狀態、非線程安全對象,不能跨線程共享。

傳統做法:Filter 創建連接/Session 綁定 ThreadLocal,業務層獲取使用,請求結束清理。缺點:樣板代碼多、事務管理分散、異常處理繁瑣。

Spring 解決方案:模板 + 聲明式事務 + ThreadLocal 整合

1. 數據源與 SessionFactory 配置

<bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close">
  <property name="driverClassName" value="${jdbc.driverClassName}"/>
  <property name="url" value="${jdbc.url}"/>
  <property name="username" value="${jdbc.username}"/>
  <property name="password" value="${jdbc.password}"/>
</bean>

<bean id="sessionFactory" class="org.springframework.orm.hibernate.LocalSessionFactoryBean">
  <property name="dataSource" ref="dataSource"/>
  <property name="mappingDirectoryLocations">
    <list><value>classpath:</value></list>
  </property>
  <property name="hibernateProperties">
    <props>
      <prop key="hibernate.dialect">net.sf.hibernate.dialect.HSQLDialect</prop>
      <prop key="hibernate.show_sql">true</prop>
    </props>
  </property>
</bean>

2. DAO 使用 HibernateTemplate

public interface CustomerDAO {
    void createCustomer(Customer customer);
}

public class HibernateCustomerDAO implements CustomerDAO {
    private HibernateTemplate hibernateTemplate;

    public void setSessionFactory(SessionFactory sf) {
        this.hibernateTemplate = new HibernateTemplate(sf, false); // false=不允許創建新 Session
    }

    public void createCustomer(Customer customer) {
        hibernateTemplate.save(customer); // 自動參與綁定到線程的 Session
    }
}

HibernateTemplate 線程安全(無實例狀態),封裝異常轉換、資源清理、最佳實踐。

3. 聲明式事務管理

<bean id="transactionManager" class="org.springframework.orm.hibernate.HibernateTransactionManager">
  <property name="sessionFactory" ref="sessionFactory"/>
</bean>

<bean id="customerDAO" class="org.springframework.transaction.interceptor.TransactionProxyFactoryBean">
  <property name="transactionManager" ref="transactionManager"/>
  <property name="target" ref="customerDAOTarget"/>
  <property name="transactionAttributes">
    <props>
      <prop key="create*">PROPAGATION_REQUIRED</prop>
      <prop key="*">PROPAGATION_REQUIRED</prop>
    </props>
  </property>
</bean>

4. 運行時流程

  1. 調用代理對象 createCustomer()。
  2. TransactionProxyFactoryBean 攔截,委託 HibernateTransactionManager。
  3. 事務管理器檢查 ThreadLocal 是否綁定 Session:
    • 無 → 創建新 Session,綁定 ThreadLocal,開啟事務。
    • 有 → 直接使用,加入現有事務。
  4. DAO 執行 HibernateTemplate.save(),自動使用綁定 Session。
  5. 方法正常返回 → 提交事務,解綁並關閉 Session。
  6. 拋出未檢查異常 → 回滾事務。

總結

Spring 通過 ThreadLocal 綁定資源 + 模板封裝最佳實踐 + AOP 聲明式事務,實現了:

  • 數據庫資源線程隔離,零同步開銷。
  • 事務管理與業務代碼完全解耦。
  • 異常統一轉換、資源自動清理。
  • 支持 JDBC、Hibernate、JDO、iBATIS、TopLink 多種持久化技術。

這是企業級 Spring 應用線程安全的標準架構。

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