服務數據對象 (Service Data Objects, SDO) 是簡化 J2EE 數據編程的統一框架,提供跨層、跨數據源的統一數據訪問模型。本文系統闡述 SDO 架構組成、核心接口、動態 API 實現原理,並通過完整示例演示客戶端-DMS 交互、數據圖構建、變更摘要追蹤、異步持久化全流程。
| 痛點 | SDO 解決方案 |
|---|---|
| J2EE 數據編程模型過於複雜 (JDBC/JPA/EJB/JCA 並存) | 統一 API 訪問關係數據庫、EJB、XML、Web Service、JCA 等異構數據源 |
| 分層架構中數據傳輸模式混亂 (DTO/VO/Entity Bean 混用) | 標準化 Data Graph 作為跨層數據載體,內建變更追蹤 |
| 離線/斷開連接編程模式缺乏標準支持 | 原生支持離線數據圖修改,重連時增量同步 |
| XML 數據綁定與 Java 對象映射割裂 | 無縫集成 XML Schema (XSD) 定義模型,序列化為標準 XML |
| 缺乏經驗證的 J2EE 模式最佳實踐封裝 | 內建 Value Object、Session Facade、Data Transfer Object 等模式 |
| 技術 | 關注點 | 與 SDO 關係 |
|---|---|---|
| JDO (Java Data Objects) | 持久層對象映射、查詢 | SDO 可作為 JDO 之上的數據傳輸層 (DTO 模式) |
| JAXB (XML Binding) | XML ↔ Java 對象綁定 | SDO 綁定範圍更廣 (XML/關係/服務),支持動態/靜態 API |
| EMF (Eclipse Modeling Framework) | 元模型驅動代碼生成、運行時反射 | SDO 參考實現基於 EMF,SDO 對象 = 實現 DataObject 接口的 EMF 對象 |
| ADO.NET | .NET 平台統一數據訪問 | 平台對應物:SDO for Java/J2EE,ADO.NET for .NET |
get/set(String path)、get/set(int index)、get/set(Property)get("department[number=123]")createDataObject()、delete()getRootObject()getChangeSummary()beginLogging()/endLogging() 控制記錄週期Property:屬性元數據 (名稱、類型、多重性、容器關係)Type:類型定義 (基本類型、DataObject 類型)Sequence:保持屬性順序的高級結構emf-sdo-xsd-SDK-2.0.1.zip (含源碼、運行時、文檔)eclipse/plugins/...)
3. 驗證:Help → About → Plug-in Details → 確認 org.eclipse.emf.* 版本 2.0.1
4. 關鍵插件:org.eclipse.emf.commonj.sdo、org.eclipse.emf.ecore.sdo (運行時必需)


public interface EmployeeDMS {
DataGraph get(String employeeName); // 查詢構建 DataGraph
void update(DataGraph dataGraph); // 根據變更摘要更新數據源
}
// 獲取 DataGraph
DataGraph employeeGraph = mediator.get(employeeName);
DataObject root = employeeGraph.getRootObject();
// 動態 API 遍歷
DataObject theManager = root.getDataObject("manager");
DataObject employee = theManager.getDataObject("employees.0"); // 索引訪問
// 讀取屬性
System.out.println("Name: " + employee.getString("name"));
System.out.println("Number: " + employee.getInt("number"));
System.out.println("Is manager?: " + (employee.getBoolean("manager") ? "yes" : "no"));
// 修改屬性 (離線修改)
employee.setString("department", newDepartmentName);
// 提交更新
mediator.update(employeeGraph);
// 創建 EClass
EClass employeeClass = ecoreFactory.createEClass();
employeeClass.setName("Employee");
// 屬性
EAttribute nameFeature = ecoreFactory.createEAttribute();
nameFeature.setName("name"); nameFeature.setEType(ecorePackage.getEString());
// 引用 (包含關係)
EReference employeesRef = ecoreFactory.createEReference();
employeesRef.setName("employees");
employeesRef.setEType(employeeClass);
employeesRef.setContainment(true); // 關鍵:包含關係確保子對象在 DataGraph 內
employeesRef.setUpperBound(-1); // 多重性 0..*
// 封裝為 EPackage
EPackage employeePackage = ecoreFactory.createEPackage();
employeePackage.getEClassifiers().add(employeeClass);
employeePackage.setNsURI("https://com.example.company.ecore");
employeePackage.setNsPrefix("company");
// 【核心】指定工廠生成 SDO DataObject 而非普通 EMF EObject
employeePackage.setEFactoryInstance(new DynamicEDataObjectImpl.FactoryImpl());
// 創建對象實例
EObject bigBoss = EcoreUtil.create(employeeClass);
bigBoss.eSet(nameFeature, "The Big Boss");
bigBoss.eSet(numberFeature, 1);
// ... 設置其他屬性
// 建立包含關係
((List) bigBoss.eGet(employeesRef)).add(terence);
// 創建 DataGraph 並設置根對象
EDataGraph employeeGraph = SDOFactory.eINSTANCE.createEDataGraph();
employeeGraph.setERootObject(bigBoss);
// 【關鍵】啟用變更記錄
employeeGraph.getChangeSummary().beginLogging();
public void update(DataGraph dataGraph) {
ChangeSummary changeSummary = dataGraph.getChangeSummary();
changeSummary.endLogging(); // 結束記錄,生成最終變更集
// 遍歷所有修改對象
for (DataObject changedObj : changeSummary.getChangedDataObjects()) {
System.out.print("DMS updating " + changedObj.getString("name"));
for (ChangeSummary.Setting setting : changeSummary.getOldValues(changedObj)) {
Property prop = setting.getProperty();
Object oldVal = setting.getValue();
Object newVal = changedObj.get(prop);
System.out.print(" (changed: " + prop.getName() + " from \"" + oldVal + "\" to \"" + newVal + "\")");
// 實際場景:執行 UPDATE SQL、調用 EJB setter、發送 JCA 交互
}
System.out.println();
}
// 同理處理創建/刪除對象:changeSummary.getCreatedDataObjects()、getDeletedDataObjects()
}
((EDataGraph)dataGraph).getDataGraphResource().save(System.out, null) 輸出標準 XML

| 決策點 | 選項 A | 選項 B | 建議 |
|---|---|---|---|
| 模型定義 | 動態 EMF API (運行時構建) | 靜態代碼生成 (XSD/UML → Java) | 原型/動態場景用動態;生產穩定模型用靜態 |
| DMS 構建 DataGraph | EMF API (eSet/eGet) - 高性能 | SDO String API (set/get) - 便利但慢 | 性能敏感用 EMF API,緩存 Property/Type 對象 |
| 變更處理 | SDO ChangeSummary - 標準、可移植 | EMF ChangeDescription - 更豐富 (如索引級刪除) | 大批量集合變更用 EMF API,常規用 SDO API |
| 包含關係 | setContainment(true) | 非包含引用 | 層次數據必須 true,否則子對象不在 DataGraph、變更不可追蹤 |
SDO 以 Data Graph + ChangeSummary 為核心,實現了跨層、跨數據源、離線友好的統一數據編程模型。其基於 EMF 的參考實現提供了動態/靈活的運行時能力,同時支持靜態代碼生成滿足性能需求。掌握 模型定義 → 實例構建 → 變更追蹤 → 增量同步 全鏈路,是構建現代化企業級數據服務層的關鍵技能。隨著 SDO 規範在 JCP 標準化推進,其在 SOA、微服務數據一致性、異構系統集成中的價值將進一步釋放。