persistence.xml 是 JPA 標準配置描述符,但不同 Provider (Hibernate、EclipseLink/TopLink)、不同運行環境 (Java SE、Java EE / Jakarta EE) 的配置差異極大。本文系統對比兩大主流 Provider 在 SE/EE 環境下的完整配置模板,並解析核心屬性差異與遷移陷阱。
<?xml version="1.0" encoding="UTF-8"?>
<persistence 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_2.xsd"
version="2.2">
<persistence-unit name="PU_Name" transaction-type="RESOURCE_LOCAL | JTA">
<provider>FQCN of Provider</provider>
<jta-data-source>JNDI Name</jta-data-source>
<non-jta-data-source>JNDI Name</non-jta-data-source>
<class>com.example.Entity</class>
<exclude-unlisted-classes>true/false</exclude-unlisted-classes>
<properties>
... Provider 專屬屬性 ...
</properties>
</persistence-unit>
</persistence>
<persistence-unit name="HibernateSE" transaction-type="RESOURCE_LOCAL">
<provider>org.hibernate.jpa.HibernatePersistenceProvider</provider>
<class>com.example.User</class>
<class>com.example.Order</class>
<exclude-unlisted-classes>true</exclude-unlisted-classes>
<properties>
<!-- JDBC 連接 -->
<property name="jakarta.persistence.jdbc.driver" value="org.postgresql.Driver"/>
<property name="jakarta.persistence.jdbc.url" value="jdbc:postgresql://localhost:5432/mydb"/>
<property name="jakarta.persistence.jdbc.user" value="dbuser"/>
<property name="jakarta.persistence.jdbc.password" value="dbpass"/>
<!-- Hibernate 專屬 -->
<property name="hibernate.dialect" value="org.hibernate.dialect.PostgreSQLDialect"/>
<property name="hibernate.hbm2ddl.auto" value="update"/>
<property name="hibernate.show_sql" value="true"/>
<property name="hibernate.format_sql" value="true"/>
<property name="hibernate.connection.pool_size" value="10"/>
<property name="hibernate.current_session_context_class" value="thread"/>
</properties>
</persistence-unit>
<persistence-unit name="EclipseLinkSE" transaction-type="RESOURCE_LOCAL">
<provider>org.eclipse.persistence.jpa.PersistenceProvider</provider>
<class>com.example.User</class>
<exclude-unlisted-classes>true</exclude-unlisted-classes>
<properties>
<property name="jakarta.persistence.jdbc.driver" value="org.postgresql.Driver"/>
<property name="jakarta.persistence.jdbc.url" value="jdbc:postgresql://localhost:5432/mydb"/>
<property name="jakarta.persistence.jdbc.user" value="dbuser"/>
<property name="jakarta.persistence.jdbc.password" value="dbpass"/>
<!-- EclipseLink 專屬 -->
<property name="eclipselink.ddl-generation" value="create-tables"/>
<property name="eclipselink.ddl-generation.output-mode" value="database"/>
<property name="eclipselink.logging.level" value="FINE"/>
<property name="eclipselink.target-database" value="PostgreSQL"/>
</properties>
</persistence-unit>
<persistence-unit name="HibernateEE" transaction-type="JTA">
<provider>org.hibernate.jpa.HibernatePersistenceProvider</provider>
<jta-data-source>java:/jdbc/MyDS</jta-data-source>
<!-- EE 環境下容器掃描實體類,通常無需 -->
<properties>
<property name="hibernate.hbm2ddl.auto" value="update"/>
<property name="hibernate.show_sql" value="true"/>
<property name="hibernate.transaction.jta.platform" value="org.hibernate.service.jta.platform.internal.JBossAppServerJtaPlatform"/>
</properties>
</persistence-unit>
<persistence-unit name="EclipseLinkEE" transaction-type="JTA">
<provider>org.eclipse.persistence.jpa.PersistenceProvider</provider>
<jta-data-source>jdbc/MyDS</jta-data-source>
<properties>
<property name="eclipselink.ddl-generation" value="create-tables"/>
<property name="eclipselink.logging.level" value="FINE"/>
<property name="eclipselink.target-server" value="SunAS9"/>
</properties>
</persistence-unit>
| 維度 | Java SE | Java EE / Jakarta EE |
|---|---|---|
| transaction-type | RESOURCE_LOCAL (應用手動管理 tx) | JTA (容器管理 tx,EJB/CDI 注入 EntityManager) |
| DataSource 來源 | properties 中 JDBC URL/驅動/用戶/密碼 | <jta-data-source> JNDI 名稱,容器配置連接池 |
| 實體類發現 | 需 <class> 顯式列出或 exclude-unlisted-classes=false 掃描 | 容器自動掃描持久化單元內實體類 (可被 exclude-unlisted-classes 控制) |
| EntityManager 獲取 | Persistence.createEntityManagerFactory("PU").createEntityManager() | @PersistenceContext EntityManager em 注入 |
| 事務控制 | em.getTransaction().begin/commit/rollback() | 容器自動管理 (EJB 方法邊界) 或 UserTransaction 手動 |
| Provider 適配屬性 | 無需容器適配 | 必須 設置 hibernate.transaction.jta.platform / eclipselink.target-server 對應具體容器 |
<persistence ...>
<persistence-unit name="HibernatePU" transaction-type="RESOURCE_LOCAL">
<provider>org.hibernate.jpa.HibernatePersistenceProvider</provider>
<class>com.example.User</class>
<properties> ... Hibernate 屬性 ... </properties>
</persistence-unit>
<persistence-unit name="EclipseLinkPU" transaction-type="RESOURCE_LOCAL">
<provider>org.eclipse.persistence.jpa.PersistenceProvider</provider>
<class>com.example.User</class>
<properties> ... EclipseLink 屬性 ... </properties>
</persistence-unit>
</persistence>
運行時指定:Persistence.createEntityManagerFactory("HibernatePU") 或 "EclipseLinkPU"。注意: 同一持久化單元名稱下不能混合 Provider 屬性,否則啟動報錯。
javax.persistence.* → jakarta.persistence.*,Hibernate 專屬 hibernate.*、EclipseLink eclipselink.* 不變exclude-unlisted-classes=true 導致實體遺漏: 必須逐個 <class> 列出,或設為 false 開啟掃描 (需確保類路徑可掃描)No JTA platform available,必須按容器設置對應屬性hbm2ddl.auto=create-drop 導致啟動互刪表,生產環境統一用 validate 或 Flyway/Liquibase 管理遷移Spring Boot 3.x:
spring.datasource.*+spring.jpa.properties.hibernate.*自動組裝LocalContainerEntityManagerFactoryBean,無需persistence.xml。
Quarkus / Micronaut: 編譯期處理註解,生成元數據,啟動極快,同樣無需 XML。
新專案首選零 XML 配置框架,僅在存量系統維護、多 Provider 熱切換、非 Spring 容器 EE 部署時手寫 persistence.xml。
JPA 配置的核心複雜度在於 Provider 專屬屬性 × 運行環境 (SE/EE) × 容器適配 的排列組合。建立標準模板庫、CI 中包含多 Provider/多環境測試、遷移時逐屬性對照驗證,是驾驭這份複雜度的關鍵。