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

JPA 在 Java SE 桌面應用中實戰:NetBeans 自動生成 CRUD 應用全解析

     編輯:Java 綜合教學

前言:JPA 不只屬於 Java EE

Java Persistence API (JPA) 雖是 Java EE 規範,但 完全可以在 Java SE 環境獨立運行,無需 Web 容器。本文基於 NetBeans 8.1 自動生成的 Swing 桌面應用,深度剖析 JPA 在桌面端的實戰代碼結構、核心 API 使用與事務管理模式。

一、環境搭建與自動生成流程

1.1 數據庫準備

  • MySQL 數據庫,創建表 user (id, usernmae, password, name)
  • NetBeans Services 面板註冊 MySQL 連接

1.2 項目創建步驟

  1. New Project → Java Application,名稱 JpaExample
  2. 右鍵項目 → New → Other → Swing GUI Forms → Master Detail Form
  3. 綁定數據庫連接 → 選擇 user 表 → 勾選顯示字段
  4. 完成生成,自動產出:實體類、persistence.xml、Swing 界面、依賴庫 (EclipseLink + MySQL 驅動)

二、核心生成文件結構解析

2.1 persistence.xml - JPA 配置核心

<?xml version="1.0" encoding="UTF-8"?>
<persistence version="2.1" xmlns="https://xmlns.jcp.org/xml/ns/persistence">
    <persistence-unit name="ccPU" transaction-type="RESOURCE_LOCAL">
        <provider>org.eclipse.persistence.jpa.PersistenceProvider</provider>
        <class>com.cc.jpa.User</class>
        <properties>
            <property name="javax.persistence.jdbc.driver" value="com.mysql.jdbc.Driver"/>
            <property name="javax.persistence.jdbc.url" value="jdbc:mysql://localhost:3306/cc"/>
            <property name="javax.persistence.jdbc.user" value="root"/>
            <property name="javax.persistence.jdbc.password" value="123456"/>
            <!-- EclipseLink 特有配置 -->
            <property name="eclipselink.ddl-generation" value="none"/>
            <property name="eclipselink.logging.level" value="FINE"/>
        </properties>
    </persistence-unit>
</persistence>

關鍵配置點

  • transaction-type="RESOURCE_LOCAL":Java SE 環境本地事務,非 JTA
  • provider:EclipseLink (JPA 2.1 參考實現,原 TopLink)
  • 數據源屬性:JDBC 直連配置,無需 DataSource JNDI

2.2 User 實體類 - 註解驅動映射

@Entity
@Table(name = "user", catalog = "cc", schema = "")
@NamedQueries({
    @NamedQuery(name = "User.findAll", query = "SELECT u FROM User u"),
    @NamedQuery(name = "User.findById", query = "SELECT u FROM User u WHERE u.id = :id"),
    @NamedQuery(name = "User.findByUsernmae", query = "SELECT u FROM User u WHERE u.usernmae = :usernmae"),
    @NamedQuery(name = "User.findByPassword", query = "SELECT u FROM User u WHERE u.password = :password"),
    @NamedQuery(name = "User.findByName", query = "SELECT u FROM User u WHERE u.name = :name")
})
public class User implements Serializable {
    
    @Id
    @Basic(optional = false)
    @Column(name = "id")
    private Integer id;

    @Basic(optional = false)
    @Column(name = "usernmae")
    private String usernmae;

    @Basic(optional = false)
    @Column(name = "password")
    private String password;

    @Basic(optional = false)
    @Column(name = "name")
    private String name;

    // PropertyChangeSupport 實現屬性變更通知 (綁定框架需要)
    @Transient
    private PropertyChangeSupport changeSupport = new PropertyChangeSupport(this);
    
    // Getter/Setter 中火屬性變更事件...
    public void setUsernmae(String usernmae) {
        String old = this.usernmae;
        this.usernmae = usernmae;
        changeSupport.firePropertyChange("usernmae", old, usernmae);
    }
    // ... 其他字段類似
}

亮點解析

  • @NamedQueries:集中管理 JPQL,運行時通過名稱調用,避免硬編碼
  • PropertyChangeSupport:JavaBeans 規範,支撐 Swing 組件雙向綁定
  • @Transient:非持久化字段標記

2.3 MasterDetailForm.java - 界面與業務邏輯融合

核心初始化代碼 (構造函數中):

public MasterDetailForm() {
    initComponents(); // GUI 構建器生成的組件初始化
    
    if (!Beans.isDesignTime()) { // 非設計模式才初始化 JPA
        // 1. 創建 EntityManagerFactory (線程安全、重量級、應用級單例)
        entityManager = Persistence.createEntityManagerFactory("ccPU").createEntityManager();
        
        // 2. 開啟事務 (桌面應用常用手動事務控制)
        entityManager.getTransaction().begin();
        
        // 3. 創建查詢 (使用 NamedQuery)
        query = entityManager.createNamedQuery("User.findAll");
        
        // 4. 綁定數據源:查詢結果 → ObservableList → JTable
        list = ObservableCollections.observableList(query.getResultList());
    }
}

三、CRUD 操作核心代碼深度解析

3.1 新增 (New 按鈕)

private void newButtonActionPerformed(ActionEvent evt) {
    User u = new User();           // 1. 創建瞬態實例
    entityManager.persist(u);      // 2. 持久化 (分配 ID、納入管理)
    list.add(u);                   // 3. 更新 UI 綁定列表
    
    int row = list.size() - 1;
    masterTable.setRowSelectionInterval(row, row); // 選中新行
    masterTable.scrollRectToVisible(masterTable.getCellRect(row, 0, true));
}

3.2 刪除 (Delete 按鈕)

private void deleteButtonActionPerformed(ActionEvent evt) {
    int[] selected = masterTable.getSelectedRows();
    List toRemove = new ArrayList<>(selected.length);
    
    for (int idx : selected) {
        // 轉換視圖行索引 → 模型索引 (關鍵:排序/過濾後索引不一致)
        User u = list.get(masterTable.convertRowIndexToModel(idx));
        toRemove.add(u);
        entityManager.remove(u);   // 從持久化上下文移除 (SQL 待提交執行)
    }
    list.removeAll(toRemove);      // 更新 UI
}

3.3 保存 (Save 按鈕) - 事務提交與異常處理

private void saveButtonActionPerformed(ActionEvent evt) {
    try {
        entityManager.getTransaction().commit();  // 提交事務,執行 SQL
        entityManager.getTransaction().begin();   // 開啟新事務
    } catch (RollbackException rex) {
        rex.printStackTrace();
        entityManager.getTransaction().begin();   // 重新開啟事務
        
        // 合併策略:重新附托管實體
        List merged = new ArrayList<>(list.size());
        for (User u : list) {
            merged.add(entityManager.merge(u));   // merge 返回新的受管實體
        }
        list.clear();
        list.addAll(merged);  // 更新綁定列表為受管實體
    }
}

3.4 刷新 (Refresh 按鈕) - 數據庫同步

private void refreshButtonActionPerformed(ActionEvent evt) {
    entityManager.getTransaction().rollback();  // 回滾未提交變更
    entityManager.getTransaction().begin();     // 新事務
    
    Collection data = query.getResultList();    // 重新查詢數據庫
    for (Object entity : data) {
        entityManager.refresh(entity);          // 強制刷新實體狀態
    }
    list.clear();
    list.addAll(data);                          // 更新 UI
}

四、關鍵技術模式總結

操作核心 API事務行為UI 同步策略
新增persist()事務提交時 INSERT立即加入綁定列表
刪除remove()事務提交時 DELETE立即從綁定列表移除
修改自動髒檢查事務提交時 UPDATEPropertyChange 事件驅動
保存commit() / merge()提交/合併托管態異常時重新綁定 merge 結果
刷新rollback() / refresh()回滾 + 重讀清空列表重新加載

五、桌面應用 JPA 最佳實踐建議

✅ 核心原則

  1. EntityManager 生命周期:桌面應用通常採用 長會話模式,單個 EntityManager 伴隨界面生命周期,而非請求級
  2. 事務邊界:按用戶操作單元劃分 (如點擊保存提交),而非自動提交
  3. 異步處理:耗時查詢/保存放入 SwingWorker 避免阻塞 EDT (事件分發線程)
  4. 樂觀鎖:實體添加 @Version 字段防止併發覆蓋
  5. 提供者中立:僅使用 JPA 標準 API,可無縫切換 EclipseLink/Hibernate/OpenJPA

六、Eclipse 環境手動配置指南

NetBeans 自帶 EclipseLink,Eclipse 需手動:

  1. 下載 EclipseLink (含 javax.persistence API)
  2. 項目屬性 → Java Build Path → Libraries → Add External JARs
  3. 手寫 META-INF/persistence.xml (參考上文內容)
  4. 實體類手寫或用 JPA 圖形編輯器 (Dali/JBoss Tools) 生成

七、總結

NetBeans 自動生成的 JPA 桌面應用展示了 Java SE 環境下 JPA 完整工作流:EntityManagerFactory 創建 → EntityManager 管理實體生命周期 → 事務手動控制 → JPQL/NamedQuery 查詢 → Swing 綁定框架雙向同步。理解這套機制,可將 JPA 應用於任何 Java SE 場景:桌面客戶端、批處理程序、微服務、測試工具等,擺脫「JPA 僅限 Java EE」的誤區。

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