Amazon SimpleDB 是高擴展、高可靠、低成本的雲端 NoSQL 儲存服務,採 HTTP 通訊支援多語言。但其僅支援字串資料型別,且無標準 ORM 支援,直接使用 AWS SDK 開發較為繁瑣。本文介紹如何透過 SimpleJPA——一個開源 JPA 實現——以熟悉的 POJO + 註解方式,輕鬆實現 SimpleDB 物件持久化。
Hibernate 以 POJO 革命化 ORM 領域,催生 Java Persistence API (JPA) 標準。EJB 3.0、Google App Engine、Hibernate EntityManager 皆實現 JPA。開發者習慣 POJO 建模後,自然期望 SimpleDB 也能提供類似體驗——SimpleJPA 正是填補此空白的關鍵。
以賽跑應用為例,核心實體 Race(比賽)與 Runner(選手)呈現一對多關係:
@Entity
public class Race {
private String name;
private String location;
private BigDecimal distance; // 推薦 BigDecimal 替代 double
private List<Runner> runners;
private String id; // SimpleJPA 要求 String ID
@Id
public String getId() { return id; }
@OneToMany(mappedBy = "race")
public List<Runner> getRunners() { return runners; }
// ... 其他 getter/setter
}
@Entity
public class Runner {
private String name;
private String ssn;
private Race race;
private String id;
@Id
public String getId() { return id; }
@ManyToOne
public Race getRace() { return race; }
// ... 其他 getter/setter
}
關鍵點:
@Entity 標記持久化類@Id 定義主鍵(SimpleJPA 強制 String 型別)@OneToMany/@ManyToOne 定義雙向關係,註解置於 getter 上SimpleDB 僅儲存字串,數值查詢需字典序相容編碼。SimpleJPA 內建自動轉換:
// 內部查詢實際發送至 SimpleDB 的語句
amazonQuery: Domain=b50-Race, query=select * from `b50-Race`
where `distance` = '0922337203685477583419999999999999928946'
開發者完全無需感知編碼細節,直接使用數值型別建模與查詢。
SimpleJPA 提供基礎類 IdedTimestampedBase,自動管理 ID、created、updated 欄位(底層由 SimpleDB 產生唯一 ID):
@Entity
public class Race extends IdedTimestampedBase {
private String name;
private String location;
private BigDecimal distance;
private List<Runner> runners;
// ... 註解與方法同前
}
Map<String,String> props = new HashMap<>();
props.put("accessKey", "YOUR_AWS_ACCESS_KEY");
props.put("secretKey", "YOUR_AWS_SECRET_KEY");
EntityManagerFactoryImpl factory = new EntityManagerFactoryImpl("b50", props);
// "b50" 為域前綴,實際域名為 "b50-Race", "b50-Runner"
EntityManager em = factory.createEntityManager();
// 建立比賽
Race race = new Race();
race.setName("Taipei Marathon");
race.setLocation("Taipei, Taiwan");
race.setDistance(new BigDecimal("42.195"));
em.persist(race);
// JPA 查詢(不支援 Join)
Query query = em.createQuery("select o from Race o where o.distance = :dist");
query.setParameter("dist", new BigDecimal("42.195"));
List<Race> races = query.getResultList();
// 關係操作:建立選手並關聯比賽
Runner runner = new Runner();
runner.setName("John Chen");
runner.setSsn("A123456789");
runner.setRace(race);
race.getRunners().add(runner);
em.persist(runner);
em.persist(race); // 更新比賽的選手集合
// 刪除比賽(關聯選手不會級聯刪除,可用 @EntityListeners 處理)
em.remove(race);
SimpleDB 禁止跨域 Join,SimpleJPA 採用「儲存關聯物件鍵,查詢時再載入」策略:持久化 Runner 時自動儲存其所屬 Race 的 ID,讀取 Race 時再查詢對應選手集合。這與 JPA 標準行為一致,開發體驗無縫銜接。
SimpleJPA 實現 JPA 子集,讓開發者以熟悉的 Hibernate/JPA 技能,在非關係雲端儲存中實現:
這是 Java 開發者邁向雲端 NoSQL 儲存的最平滑路徑。




