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

Spring 整合 JPA 完整指南:LocalEntityManagerFactoryBean 注入、JpaTransactionManager 事務管理、EntityManager 生命週期

     編輯:Java 綜合教學

Spring 整合 JPA:從配置到事務管理的完整實戰

1. JPA 與 Hibernate 關係釐清

  • JPA:Sun 制定的 ORM 標準規範 (javax.persistence / jakarta.persistence)
  • Hibernate:JPA 的最成熟實現,也是事實標準提供者
  • 關係:JPA 是介面,Hibernate 是實現類;Spring Data JPA 進一步封裝 Repository 抽象

2. 兩種獲取 EntityManagerFactory 方式

方式一:手動建構 (不推薦生產)

// DAO 層硬編碼,違反 IOC 原則
EntityManagerFactory emf = Persistence.createEntityManagerFactory("myJpa");
EntityManager em = emf.createEntityManager();

方式二:Spring 容器管理 (推薦,本文重點)

優勢:生命週期托管、事務整合、異常轉換、線程綁定、延遲加載支援

3. Spring XML 配置詳解

3.1 persistence.xml (JPA 標準配置,放在 src/main/resources/META-INF/)

<?xml version="1.0" encoding="UTF-8"?>
<persistence version="2.1"
    xmlns="https://xmlns.jcp.org/xml/ns/persistence"
    xmlns:xsi="https://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="https://xmlns.jcp.org/xml/ns/persistence
    https://xmlns.jcp.org/xml/ns/persistence/persistence_2_1.xsd">

    <persistence-unit name="myJpa" transaction-type="RESOURCE_LOCAL">
        <provider>org.hibernate.jpa.HibernatePersistenceProvider</provider>
        <class>entity.Product</class>
        
        <properties>
            <property name="hibernate.dialect" value="org.hibernate.dialect.MySQL8Dialect"/>
            <property name="hibernate.connection.driver_class" value="com.mysql.cj.jdbc.Driver"/>
            <property name="hibernate.connection.url" value="jdbc:mysql://localhost:3306/product_db?useSSL=false&serverTimezone=UTC"/>
            <property name="hibernate.connection.username" value="root"/>
            <property name="hibernate.connection.password" value="123456"/>
            <property name="hibernate.show_sql" value="true"/>
            <property name="hibernate.format_sql" value="true"/>
            <property name="hibernate.hbm2ddl.auto" value="update"/>
        </properties>
    </persistence-unit>
</persistence>

3.2 applicationContext.xml (Spring 核心配置)

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="https://www.springframework.org/schema/beans"
    xmlns:xsi="https://www.w3.org/2001/XMLSchema-instance"
    xmlns:tx="https://www.springframework.org/schema/tx"
    xmlns:context="https://www.springframework.org/schema/context"
    xsi:schemaLocation="
        https://www.springframework.org/schema/beans https://www.springframework.org/schema/beans/spring-beans.xsd
        https://www.springframework.org/schema/tx https://www.springframework.org/schema/tx/spring-tx.xsd
        https://www.springframework.org/schema/context https://www.springframework.org/schema/context/spring-context.xsd">

    <!-- 1. 掃描組件 -->
    <context:component-scan base-package="com.demo" />
    <context:annotation-config />

    <!-- 2. EntityManagerFactory Bean -->
    <bean id="entityManagerFactory" 
        class="org.springframework.orm.jpa.LocalEntityManagerFactoryBean">
        <property name="persistenceUnitName" value="myJpa" />
    </bean>

    <!-- 3. 事務管理器 -->
    <bean id="transactionManager" 
        class="org.springframework.orm.jpa.JpaTransactionManager">
        <property name="entityManagerFactory" ref="entityManagerFactory" />
    </bean>

    <!-- 4. 註解驅動事務 -->
    <tx:annotation-driven transaction-manager="transactionManager" />

</beans>

4. DAO 層實現:EntityManager 注入與使用

關鍵點:@PersistenceContext vs @Autowired

@Repository
public class ProductDaoImpl implements ProductDao {

    // 方式 1:JPA 標準註解 (推薦),自動綁定當前事務的 EntityManager
    @PersistenceContext
    private EntityManager entityManager;

    // 方式 2:Spring 自定義註解 (需 Qualifier 指定 Bean 名)
    // @Autowired
    // @Qualifier("entityManagerFactory")
    // private EntityManagerFactory entityManagerFactory; // 需手動 createEntityManager()

    @Override
    @Transactional // 方法級事務,或類級
    public Product save(Product product) {
        entityManager.persist(product);
        return product;
    }

    @Override
    @Transactional(readOnly = true)
    public Product findById(Long id) {
        return entityManager.find(Product.class, id);
    }

    @Override
    @Transactional
    public void deleteById(Long id) {
        Product product = entityManager.find(Product.class, id);
        if (product != null) {
            entityManager.remove(product);
        }
    }

    @Override
    @Transactional(readOnly = true)
    public List findAll() {
        // JPQL 查詢
        TypedQuery query = entityManager.createQuery("SELECT p FROM Product p", Product.class);
        return query.getResultList();
    }
}

5. 事務管理深度解析

6. EntityManager 生命週期與線程安全

  • @PersistenceContext 注入的是代理對象,實際委派給 TransactionSynchronizationManager 綁定的當前事務 EntityManager
  • 每個事務對應一個 EntityManager,事務提交/回滾時自動關閉
  • 非線程安全:不可作為實例變量在多線程共享,但 Spring 代理保證每線程獲取獨立實例
  • 延遲加載:事務內有效,事務外訪問拋 LazyInitializationException (OSIV 模式可解決)

7. 進階:DataSource 方式替換 persistence.xml (生產常用)

<bean id="dataSource" class="com.zaxxer.hikari.HikariDataSource">
    <property name="jdbcUrl" value="jdbc:mysql://localhost:3306/product_db"/>
    <property name="username" value="root"/>
    <property name="password" value="123456"/>
</bean>

<bean id="entityManagerFactory" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
    <property name="dataSource" ref="dataSource" />
    <property name="packagesToScan" value="entity" /> 
    <property name="jpaVendorAdapter">
        <bean class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter">
            <property name="database" value="MYSQL"/>
            <property name="showSql" value="true"/>
            <property name="generateDdl" value="true"/>
        </bean>
    </property>
    <property name="jpaProperties">
        <props>
            <prop key="hibernate.dialect">org.hibernate.dialect.MySQL8Dialect</prop>
            <prop key="hibernate.hbm2ddl.auto">update</prop>
        </props>
    </property>
</bean>

優勢:DataSource 統一管理、連接池整合、無需 persistence.xml、多數據源易擴展。

8. 常見問題排查

配置層面關鍵 Bean/註解作用
事務管理器JpaTransactionManager平台事務管理器實現,綁定 EMF
註解驅動<tx:annotation-driven> / @EnableTransactionManagement啟用 @Transactional 解析、代理織入
事務邊界@Transactional類/方法級宣告事務屬性
傳播行為propagation = REQUIRED (預設)支援巢狀事務邏輯
隔離級別isolation = READ_COMMITTED資料庫鎖策略
唯讀優化readOnly = trueHibernate 唯讀優化、資料庫鎖優化
回滾規則rollbackFor = Exception.class受檢異常預設不回滾,需顯式指定
超時timeout = 30防止長事務佔用資源
問題原因解決
No EntityManager bound事務未生效/未啟用註解驅動檢查 @EnableTransactionManagement、tx:annotation-driven、@Transactional 位置
LazyInitializationException事務外訪問懶加載關聯OSIV Filter、fetch join、DTO 投影、延長事務邊界
事務不回滾受檢異常/try-catch 吞異常rollbackFor 指定、不捕獲或重新拋出
多線程 EM 衝突手動 createEntityManager() 共享務必用 @PersistenceContext 注入代理

總結:Spring 整合 JPA 核心在於 LocalContainerEntityManagerFactoryBean + JpaTransactionManager + @PersistenceContext + @Transactional 四件套。掌握 EntityManager 代理機制、事務傳播規則、懶加載邊界,即可構建健壯的 JPA 數據訪問層。生產環境建議使用 DataSource 方式替換 persistence.xml,接入 HikariCP 連接池。

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