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

Apache Cayenne 入門實戰:從環境搭建、建模到 CRUD 完整演示

     編輯:Java 相關知識

Apache Cayenne 是 Apache 旗下成熟開源 ORM 框架,擁有可視化建模工具 CayenneModeler、零配置啟動、逆向工程、遠程持久化等特性。本文以「購物網站」為例,手把手演示環境搭建、ER 建模、代碼生成、API 實戰,助你 30 分鐘上手 Cayenne。

一、為什麼選 Cayenne?

  • ✅ 完全開源,Apache License 2.0,無商業風險
  • ✅ 可視化建模器 CayenneModeler,降低學習曲線
  • ✅ 支持多 DataDomain/DataNode/DataMap,靈活適配多庫多模式
  • ✅ 內置連接池、緩存、分頁、預讀,生產級性能
  • ✅ 獨有 ROP 遠程持久化,輕量級分布式 ORM 方案

二、環境搭建

1. 下載組件

  • Cayenne 2.0 穩定版:cayenne-2.0.zip (含 Modeler)
  • Eclipse 3.4+
  • Apache Derby 10.x (嵌入式輕量級數據庫)

2. Eclipse 專案配置

Java Project → Build Path → Add External JARs
選中 cayenne.jar、derby.jar 等所有 lib

3. 啟動 CayenneModeler

cd cayenne/bin
./cayennemodeler.sh  (Windows: cayennemodeler.bat)

三、核心概念三元組

概念角色類比
DataDomain虛擬數據域,頂層容器「租戶」或「業務域」
DataNode物理數據源,含 JDBC 配置「數據庫實例」
DataMap對象-關係映射元數據「ORM 映射文件集」

關係:DataDomain 1:N DataNode,DataNode 1:1 DataMap。本文演示 1:1:1 簡化模式。

四、建模實戰:購物網站 ER 圖

1. 創建項目結構

  • DataDomain: cayenne-store
  • DataNode: cayenne-storeNode → 選 Embedded Derby → 配置 JDBC URL
  • DataMap: cayenne-storeMap → Java Package: com.example.cayenne
  • 保存 cayenne.xml 至 src/ (Classpath 根目錄)

2. DBEntity 建模(對應數據庫表)

| 表名 | 關鍵字段 | 關係 | |------|----------|------| | CLIENT_TB | client_id (PK), name, pwd, mail | 1:N → ORDER_TB | | COMMODITY_TB | commodity_id (PK), name, price, qty | 1:N → ORDER_COMMODITY_TB | | ORDER_TB | order_id (PK), client_id (FK), date | N:1 ← CLIENT_TB, 1:N → ORDER_COMMODITY_TB | | ORDER_COMMODITY_TB | id (PK), order_id (FK), commodity_id (FK), qty | N:1 ← ORDER_TB, N:1 ← COMMODITY_TB |

Modeler 操作:Create DBEntity → 添加屬性 → Relationships 面板建立 FK 關係 → 設置 Delete Rule (CASCADE: 刪客戶級聯刪訂單)。

3. 同步生成 ObjEntity

每個 DBEntity 面板點擊 「同步 DBEntity 到 ObjEntity」,自動生成 Java 實體類映射,關係轉為對象引用 (toOne/toMany)。

4. 生成代碼與 Schema

  • Tools → Generate Classes → 輸出 Java 實體、自動生成 _Auto 基類
  • Tools → Generate Database Schema → Derby 建表腳本自動執行

Eclipse 刷新項目,即見 com.example.cayenne 包下實體類,Derby 數據庫文件生成於項目目錄。

五、核心 API 速覽

| 類/接口 | 核心職責 | 典型用法 | |---------|----------|----------| | DataContext | 會話入口,CRUD、事務、查詢執行 | DataContext.createDataContext() | | SelectQuery | 對象查詢,支援 Qualifier、Prefetch、分頁 | new SelectQuery(ClientTB.class) | | Expression | 條件構建,字符串解析 | Expression.fromString("name = $name") | | DataObject | 持久化對象,屬性+關係 | context.newObject(ClientTB.class) | | QueryChain | 批量非查詢操作 (SQLTemplate) | context.performNonSelectingQuery(chain) |

六、完整 Demo:初始化 → 查詢 → 下單

1. 清空並裝載基礎數據

// 刪除客戶與商品,級聯刪除訂單
context.deleteObject(client);
context.deleteObject(commodity);
context.commitChanges();

// 讀取 loadData.sql 腳本批量執行
QueryChain chain = new QueryChain();
BufferedReader in = new BufferedReader(new InputStreamReader(
    getClass().getResourceAsStream("/loadData.sql")));
String line;
while ((line = in.readLine()) != null) {
    if (line.endsWith(";")) line = line.substring(0, line.length()-1);
    chain.addQuery(new SQLTemplate(domain.getMap("cayenne-storeMap"), line));
}
context.performNonSelectingQuery(chain);

2. 查詢客戶及其訂單

List clients = context.performQuery("allClients");
for (ClientTB c : clients) {
    System.out.println(c.getClientName() + " " + c.getClientMail());
    for (OrderTB o : c.getOrdersOwned()) {
        StringBuilder sb = new StringBuilder();
        for (OrderCommodityTB oc : o.getCommoditiesContained()) {
            sb.append(oc.getCommoditiesBought().getComName()).append(", ");
        }
        System.out.println("  Order: " + sb + " on " + o.getOrderDate());
    }
}

3. 模擬下單流程

ClientTB buyer = context.performQuery(new SelectQuery(ClientTB.class, 
    Expression.fromString("clientName = 'YingChu'"))).get(0);

CommodityTB phone = ... get "Nokia Phone n95";
CommodityTB laptop = ... get "ThinkPad T61p";

OrderTB order = context.newObject(OrderTB.class);
order.setOrderDate(new Date());
order.setClientBelonged(buyer);  // 關聯買家

OrderCommodityTB item1 = context.newObject(OrderCommodityTB.class);
item1.setComNumber(1);
item1.setBelongedToOrders(order);
item1.setCommoditiesBought(phone);

OrderCommodityTB item2 = context.newObject(OrderCommodityTB.class);
item2.setComNumber(1);
item2.setBelongedToOrders(order);
item2.setCommoditiesBought(laptop);

// 庫存扣減
phone.setCommodityNumber(phone.getCommodityNumber() - 1);
laptop.setCommodityNumber(laptop.getCommodityNumber() - 1);

context.commitChanges();  // 一次性提交事務

七、DAO 封裝建議

項目結構建議:

dao/
├── ClientDao.java
├── CommodityDao.java
├── OrderDao.java
└── CayenneStoreDao.java  // 持有 DataContext、commitChanges() 等通用邏輯

所有 DAO 實現注入 CayenneStoreDao 獲取 DataContext,業務層調用 DAO,解耦持久化細節。

八、常見坑與避坑指南

  1. cayenne.xml 必須在 Classpath 根目錄:src/ 或 resources/,否則 DataContext.createDataContext() 拋 NullPointerException
  2. Delete Rule 設置:CASCADE 刪除父級聯刪子,NULLIFY 置空 FK,DENY 禁止刪除,NO_ACTION 交由數據庫約束
  3. DataContext 線程不安全:每請求/每線程一個實例,勿作為單例字段
  4. 預讀關係名稱:addPrefetch("orders") 參數必須與 ObjEntity Relationship 名稱完全一致,區分大小寫

九、結語與進階預告

通過本文,你已掌握 Cayenne 的環境搭建、可視化建模、代碼生成、核心 API 及完整業務流程。下一步可深入學習:

  • ROP 遠程持久化:跨 JVM/跨機器共享 ORM 能力
  • 性能優化:連接池調優、五級緩存策略、分頁與預讀組合
  • 遷移與版本控制:映射文件演進、數據庫遷移腳本管理

CayenneModeler + 零 XML 配置 + 豐富企業級特性,讓 ORM 回歸「領域建模」本質。開始你的 Cayenne 之旅吧!

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