因為 Spring Data JPA 用來存取資料庫時很方便,然後 DynamoDB 又是屬於特別囉唆的東西,所以之前在研究 Spring Boot 時,就在想不知道 Spring 是否有支援 DynamoDB 的實作。很幸運地,社群真的有人做了 Spring Data JPA + DynamoDB [1-2] 造福大家!XD
Maven
使用 Spring Data JPA + DynamoDB 的狀況,自然需要的一定是 Spring 的環境以及橋接 DynamoDB 的實作。這裡使用的 Spring 環境是透過 Spring Boot 建立的,Maven 設定如下:
<dependencyManagement> <dependencies> <dependency> <groupId>com.amazonaws</groupId> <artifactId>aws-java-sdk-bom</artifactId> <version>1.11.301</version> <type>pom</type> <scope>import</scope> </dependency> </dependencies> </dependencyManagement> <parent> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-parent</artifactId> <version>2.0.2.RELEASE</version> </parent> <dependencies> <!-- Spring Boot --> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-data-jpa</artifactId> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-context-indexer</artifactId> </dependency> <!-- Amazon SDKs --> <dependency> <groupId>com.amazonaws</groupId> <artifactId>aws-java-sdk-dynamodb</artifactId> </dependency> <dependency> <groupId>com.github.derjust</groupId> <artifactId>spring-data-dynamodb</artifactId> <version>5.0.2</version> </dependency> </dependencies>
上頭的第一部份(1~11 行)是指定 AWS SDK 的版本,這個版本其實是以 [1] 所使用的版本(1.11.301)為準;第二部份(13~17 行)是指定 Spring Boot 的版本,也就是後面的 dependency 中用到 Spring Boot 的時候,都會從這裡決定版號;第三部份就是真的需要的函式庫的引用了,其中 35~39 行宣告的 spring-data-dynamodb 就是本篇的重點 [1],也就是真正提供 DynamoDB 和 Spring Data JPA 串接的函式庫。
如果說想要使用的 Spring 或者 Spring Boot 版本不是 Spring Boot 2.0 以上,那麼可以參考 [1] 的版本資訊去尋找合適的對應版本。
建立 Entity
假設我在 DynamoDB 的 table 中存放的每個 record 要叫做 MyRecord,並且他是個具有複合主鍵(也就是有 Partition Key 和 Sort Key)的特性,那麼就需要按照 Spring Data JPA 本來的結構,做出一個代表主鍵的物件(這裡命名為 RecordId)。不過除此之外,還有一點特殊需要注意的地方。
首先先假設 record 的結構包含了 my_pk、my_sk、display_name 和 flag 這四個欄位,其中 my_pk、my_sk 組成複合主鍵,則 Entity 可以寫成以下的樣子:
MyRecord.java
@DynamoDBTable(tableName = "my_table") public class MyRecord implements Serializable { @Id private RecordId id; private String displayName; private Boolean flag; @DynamoDBHashKey(attributeName = "my_pk") public String getPartition () { return this.id.getPartition(); } @DynamoDBRangeKey(attributeName = "my_sk") public Long getEpochTime () { return this.id.getEpochTime(); } @DynamoDBAttribute(attributeName = "display_name") public String getDisplayName () { return this.displayName; } @DynamoDBAttribute(attributeName = "flag") public Boolean getFlag () { return this.flag; } public void setPartition (String val) { if (this.id == null) { this.id = new RecordId(); } this.id.setPartition(val); } public void setEpochTime (String val) { if (this.id == null) { this.id = new RecordId(); } this.id.setEpochTime(val); } public void setDisplayName (String val) { this.displayName = val; } public void setFlag (Boolean val) { this.flag = val; } }
MyRecord.java
public class RecordId implements Serializable { private String partition; private Long epochTime; @DynamoDBHashKey(attributeName = "my_pk") public String getPartition () { return this.getPartition(); } @DynamoDBRangeKey(attributeName = "my_sk") public Long getEpochTime () { return this.getEpochTime(); } public void setPartition (String val) { this.partition = val; } public void setEpochTime (Long val) { this.epochTime = val; } }
這裡可以看到比較奇妙的地方,在 MyRecord 以及 RecordId 兩處都同時寫了 @DynamoDBHashKey 和 @DynamoDBRangeKey。雖然不太確定為什麼要這樣寫,不過實務上有一邊沒寫都會導致在存取 Repository 時丟出 Exception。
這裡順利做完以後,其實最困難(?!)的地方已經完成了 XD
Entity 注意事項
- Entity 上的所有 get method 都應該要有 @DynamoDBHashKey、@DynamoDBRangeKey 或者 @DynamoDBAttribute。
- Entity 的 get method 命名一定要以 get 開頭,不能是 is…. 或者 has…. 之類的其他動詞。
- Boolean 預設會以數字形式儲存,想要強制使用 Boolean 時,需要透過 @DynamoDBTyped 指定。
建立 Repository
接下來就是標準的 Spring Data JPA 程序了。假設要使用的是 CrudRepository,那麼 Repository 的介面就這麼寫:
public interface MyRepository extends CrudRepository<MyRecord, RecordId> { }
建立 DynamoDB 設定
DynamoDB 設定主要是要提供 Spring 能夠用來存取 DynamoDB 的 Bean,因為在 DynamoDB 這個案例,建立資料庫連線的方式不同於一般 RDBMS 那樣,它不是透過 JDBC,所以需要比較不同的方式注入供 spring-data-dynamodb 存取。
@Configuration @EnableDynamoDBRepositories(basePackages = "com.example") public class DynamodbConfiguration { @Bean public AmazonDynamoDB amazonDynamoDB() { return AmazonDynamoDBClientBuilder.defaultClient(); } }
這段主要目的就是提供初始化 AmazonDynamoDB 的方法,因為我的狀況通常都會讓程式自己去環境上取得 credential(例如由 VM 的 Role 取得權限),所以這裡單純就是產生一個預設的 client 即可。如果要產生的 client 有特殊的產生過程,也可以在這裡做修改。
設定 Spring Boot 應用程式
@ComponentScan @SpringBootApplication(exclude = {DataSourceAutoConfiguration.class}) public class Application { public static void main (String[] args) { SpringApplication.run(Application.class, ARGS); } }
這段稍微特別一點的地方在於,@SpringBootApplication 的宣告上,同時宣告了要關閉 DataSource 的自動設定。關閉的原因是因為正常來說,Spring Data JPA 會去尋找 application.xml 設定檔,以得知如何透過 JDBC 模式取得資料庫的連線。但是 DynamoDB 有自己獨特的連線方法,因此要讓 Spring Data JPA 略過這個動作。不過如 [1] 的說明那樣,直接提供一個沒有內容的設定檔其實也是可以的。
做到這裡,其實就已經差不多了,最後剩下的就是讓 Spring 注入上面建立的 MyRepository,然後就可以開始快樂(?)地操作 DynamoDB 了。
沒有留言:
張貼留言