メインコンテンツまでスキップ
バージョン: 3.13

Spring Data JDBC for ScalarDB を使用した ScalarDB Cluster SQL をはじめよう

注記

このページは英語版のページが機械翻訳されたものです。英語版との間に矛盾または不一致がある場合は、英語版を正としてください。

このチュートリアルでは、Spring Data JDBC for ScalarDB を介して ScalarDB Cluster SQL を使用してサンプルアプリケーションを作成する方法について説明します。

このサンプルアプリケーションの前提条件

注記

このサンプルアプリケーションは、Eclipse Temurin の OpenJDK でテストされています。ただし、ScalarDB 自体は、さまざまなベンダーの JDK ディストリビューションでテストされています。互換性のある JDK ディストリビューションを含む ScalarDB の要件の詳細については、要件を参照してください。

サンプルアプリケーション

このチュートリアルでは、Spring Data JDBC for ScalarDB を使用して、クレジットラインでアイテムを注文して支払うことができるサンプル電子商取引アプリケーションを作成するプロセスについて説明します。

次の図は、サンプルアプリケーションのシステムアーキテクチャを示しています。

                                 +------------------------------------------------------------------------------------------------------------------------------+
| [Kubernetes クラスター] |
| |
| [ポッド] [ポッド] [ポッド] |
+------------------------+ | |
| SQL CLI | | +-------+ +------------------------+ |
| (間接クライアントモード) | --+ | +---> | Envoy | ---+ +---> | ScalarDB Cluster ノード | ---+ |
+------------------------+ | | | +-------+ | | +------------------------+ | |
| | | | | | |
| | +---------+ | +-------+ | +--------------------+ | +-----------------------+ | +------------+ |
+--+-> | サービス | ---+---> | Envoy | ---+---> | サービス | ---+---> | ScalarDB Cluster ノード | ---+---> | PostgreSQL | |
+------------------------+ | | | (Envoy) | | +-------+ | | (ScalarDB Cluster) | | +-----------------------+ | +------------+ |
| Spring Data JDBC for | | | +---------+ | | +--------------------+ | | |
| ScalarDB の | | | | +-------+ | | +------------------------+ | |
| サンプルアプリケーション | --+ | +---> | Envoy | ---+ +---> | ScalarDB Cluster ノード | ---+ |
| (間接クライアントモード) | | +-------+ +-----------------------+ |
+------------------------+ | |
+------------------------------------------------------------------------------------------------------------------------------+

ステップ 1. ScalarDB サンプルリポジトリをクローンする

git clone https://github.com/scalar-labs/scalardb-samples.git
cd scalardb-samples/spring-data-sample

ステップ 2. scalardb-sql.properties を変更する

ScalarDB Cluster に接続するには、scalardb-sql.properties も変更する必要があります。ただし、その前に、次のように Envoy (scalardb-cluster-envoy) のサービスリソースの EXTERNAL-IP アドレスを取得する必要があります。

kubectl get svc scalardb-cluster-envoy
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
scalardb-cluster-envoy LoadBalancer 10.105.121.51 localhost 60053:30641/TCP 16h

この場合、EXTERNAL-IP アドレスは localhost です。

次に、scalardb-sql.properties を開きます。

vim scalardb-sql.properties

次に、scalardb-sql.properties を次のように変更します。

scalar.db.sql.connection_mode=cluster
scalar.db.sql.cluster_mode.contact_points=indirect:localhost

ScalarDB Cluster に接続するには、scalar.db.sql.connection_mode プロパティに cluster を指定する必要があります。

また、このチュートリアルでは indirect クライアントモードを使用して Envoy のサービスリソースに接続します。

クライアントモードの詳細については、Java API を使用した ScalarDB Cluster の開発者ガイドを参照してください。

ステップ 3. スキーマをロードする

スキーマをロードするには、SQL CLI を使用する必要があります。SQL CLI は ScalarDB リリースからダウンロードできます。JAR ファイルをダウンロードしたら、次のコマンドを実行して Cluster 用の SQL CLI を使用できます。

java -jar scalardb-cluster-sql-cli-3.13.1-all.jar --config scalardb-sql.properties --file schema.sql

ステップ 4.application.propertiesを変更する

次に、ScalarDB Cluster に接続するために application.properties も変更する必要があります。

vim src/main/resources/application.properties

scalardb-sql.properties と同様に、scalar.db.sql.connection_mode プロパティに cluster を指定し、indirect クライアントモードを使用する必要があります。そのためには、application.properties を次のように変更します。

spring.datasource.driver-class-name=com.scalar.db.sql.jdbc.SqlJdbcDriver
spring.datasource.url=jdbc:scalardb:\
?scalar.db.sql.connection_mode=cluster\
&scalar.db.sql.cluster_mode.contact_points=indirect:localhost\
&scalar.db.consensus_commit.isolation_level=SERIALIZABLE\
&scalar.db.sql.default_namespace_name=sample

ステップ 5. 初期データをロードする

サンプルアプリケーションを実行する前に、次のコマンドを実行して初期データをロードする必要があります。

./gradlew run --args="LoadInitialData"

初期データがロードされた後、次のレコードがテーブルに保存される必要があります。

  • sample.customers テーブルの場合:
customer_idnamecredit_limitcredit_total
1Yamada Taro100000
2Yamada Hanako100000
3Suzuki Ichiro100000
  • sample.items テーブルの場合:
item_idnameprice
1Apple1000
2Orange2000
3Grape2500
4Mango5000
5Melon3000

ステップ 6. サンプルアプリケーションを実行する

まず、ID が 1 である顧客に関する情報を取得します。

./gradlew run --args="GetCustomerInfo 1"
...
{"customer_id":1,"name":"Yamada Taro","credit_limit":10000,"credit_total":0}
...

次に、顧客 ID 1 を使用して、リンゴ 3 個とオレンジ 2 個を注文します。注文形式は <Item ID>:<Count>,<Item ID>:<Count>,... であることに注意してください。

./gradlew run --args="PlaceOrder 1 1:3,2:2"
...
{"order_id":"2358ab35-5819-4f8f-acb1-12e73d97d34e","customer_id":1,"timestamp":1677478005400}
...

このコマンドを実行すると、注文 ID が表示されます。

注文 ID を使用して注文の詳細を確認してみましょう。

./gradlew run --args="GetOrder 2358ab35-5819-4f8f-acb1-12e73d97d34e"
...
{"order_id":"2358ab35-5819-4f8f-acb1-12e73d97d34e","timestamp":1677478005400,"customer_id":1,"customer_name":"Yamada Taro","statements":[{"item_id":1,"item_name":"Apple","price":1000,"count":3,"total":3000},{"item_id":2,"item_name":"Orange","price":2000,"count":2,"total":4000}],"total":7000}
...

次に、別の注文を出して、顧客 ID 1 の注文履歴を取得しましょう。

./gradlew run --args="PlaceOrder 1 5:1"
...
{"order_id":"46062b16-b71b-46f9-a9ff-dc6b0991259b","customer_id":1,"timestamp":1677478201428}
...
./gradlew run --args="GetOrders 1"
...
[{"order_id":"46062b16-b71b-46f9-a9ff-dc6b0991259b","timestamp":1677478201428,"customer_id":1,"customer_name":"Yamada Taro","statements":[{"item_id":5,"item_name":"Melon","price":3000,"count":1,"total":3000}],"total":3000},{"order_id":"2358ab35-5819-4f8f-acb1-12e73d97d34e","timestamp":1677478005400,"customer_id":1,"customer_name":"Yamada Taro","statements":[{"item_id":1,"item_name":"Apple","price":1000,"count":3,"total":3000},{"item_id":2,"item_name":"Orange","price":2000,"count":2,"total":4000}],"total":7000}]
...

この注文履歴は、タイムスタンプの降順で表示されます。

顧客の現在の credit_total10000 です。顧客は、情報を取得したときに表示された credit_limit に達したため、これ以上注文することはできません。

./gradlew run --args="GetCustomerInfo 1"
...
{"id": 1, "name": "Yamada Taro", "credit_limit": 10000, "credit_total": 10000}
...
./gradlew run --args="PlaceOrder 1 3:1,4:1"
...
java.lang.RuntimeException: Credit limit exceeded. limit:10000, total:17500
at sample.SampleService.placeOrder(SampleService.java:102)
at sample.SampleService$$FastClassBySpringCGLIB$$1123c447.invoke(<generated>)
at org.springframework.cglib.proxy.MethodProxy.invoke(MethodProxy.java:218)
at org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.invokeJoinpoint(CglibAopProxy.java:793)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:163)
at org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.proceed(CglibAopProxy.java:763)
at org.springframework.transaction.interceptor.TransactionInterceptor$1.proceedWithInvocation(TransactionInterceptor.java:123)
at org.springframework.transaction.interceptor.TransactionAspectSupport.invokeWithinTransaction(TransactionAspectSupport.java:388)
at org.springframework.transaction.interceptor.TransactionInterceptor.invoke(TransactionInterceptor.java:119)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186)
at org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.proceed(CglibAopProxy.java:763)
at org.springframework.aop.framework.CglibAopProxy$DynamicAdvisedInterceptor.intercept(CglibAopProxy.java:708)
at sample.SampleService$$EnhancerBySpringCGLIB$$a94e1d9.placeOrder(<generated>)
at sample.command.PlaceOrderCommand.call(PlaceOrderCommand.java:37)
at sample.command.PlaceOrderCommand.call(PlaceOrderCommand.java:13)
at picocli.CommandLine.executeUserObject(CommandLine.java:2041)
at picocli.CommandLine.access$1500(CommandLine.java:148)
at picocli.CommandLine$RunLast.executeUserObjectOfLastSubcommandWithSameParent(CommandLine.java:2461)
at picocli.CommandLine$RunLast.handle(CommandLine.java:2453)
at picocli.CommandLine$RunLast.handle(CommandLine.java:2415)
at picocli.CommandLine$AbstractParseResultHandler.execute(CommandLine.java:2273)
at picocli.CommandLine$RunLast.execute(CommandLine.java:2417)
at picocli.CommandLine.execute(CommandLine.java:2170)
at sample.SampleApp.run(SampleApp.java:26)
at org.springframework.boot.SpringApplication.callRunner(SpringApplication.java:768)
at org.springframework.boot.SpringApplication.callRunners(SpringApplication.java:752)
at org.springframework.boot.SpringApplication.run(SpringApplication.java:314)
at org.springframework.boot.SpringApplication.run(SpringApplication.java:1303)
at org.springframework.boot.SpringApplication.run(SpringApplication.java:1292)
at sample.SampleApp.main(SampleApp.java:35)
...

支払いが完了すると、顧客は再度注文できるようになります。

./gradlew run --args="Repayment 1 8000"
...
./gradlew run --args="GetCustomerInfo 1"
...
{"customer_id":1,"name":"Yamada Taro","credit_limit":10000,"credit_total":2000}
...
./gradlew run --args="PlaceOrder 1 3:1,4:1"
...
{"order_id":"0350947a-9003-46f2-870e-6aa4b2df0f1f","customer_id":1,"timestamp":1677478728134}
...

サンプルアプリケーションのソースコード

Spring Data JDBC for ScalarDB の詳細については、サンプルアプリケーションのソースコードを確認してください。

参照

その他の ScalarDB Cluster チュートリアルについては、以下を参照してください。

Java API で ScalarDB Cluster を使用するアプリケーションの開発の詳細については、以下を参照してください。

ScalarDB Cluster gRPC API の詳細については、以下を参照してください。