尝试在WSL Ubuntu上运行ScalarDB(创建示例应用程序部分)

本篇文章是有关创建样本应用程序部分,在此我将运行 ScalarDB 的样本应用程序。

“Environment setup section is here.”
「环境搭建部分在这里。」

使用ScalarDB进行操作。

ScalarDB的操作组件有两个,分别是Storage组件和Transaction组件。

存储组件

这个组件具有以下功能。

    • アトミックなCRUD操作

 

    • 逐次一貫性のサポート

 

    • 原子性/線形性条件下でのデータ変更(Create/Update/Delete)

 

    レコードごとにユーザ定義のメタデータを含める

此外,此处的键的作用是与Cassandra的分区键和聚簇键对应,可以通过列表或逗号分隔的形式进行多个定义。

此外,ScalarDB的存储组件为CRUD操作提供了四个函数。

    • Get:1件のエントリーを取得する

 

    • Put:1件のエントリーを挿入/更新する

 

    • Delete:1件のエントリーを削除する

 

    Scan:特定のパーティション内のエントリーを複数件取得する

交易组件

该组件不仅包含Storage组件的功能,还提供了无主事务功能。

如果要使用事务功能,首先需要获取TransactionService实例。然后,在TransactionService实例上执行Get、Put、Delete和Scan操作之后,将事务实例提交并将操作内容反映到数据库中。

样本应用程序

我们将在样例应用程序中验证ScalarDB的实际应用运行情况。

应用程序的概述

    • ユーザごとに口座を持つ

 

    • 口座に指定した金額をチャージ

 

    • 口座から別の口座へ支払い

 

    口座の残高を確認

我們將實施具有這些功能的樣例應用程式。

image.png

定义模式

image.png

KEYSPACE: emoney
TABLE: account
列:
– group_id: 分组ID(分区键)
– id: 用户ID(聚簇键)
– balance: 用户的余额

处理的步骤

充电

    1. 获取指定用户的信息

 

    1. 在获取的用户信息中添加充值金额

 

    将更新后的信息写入

在一个事务内执行上述一系列操作。

付款

    1. 获取发送人和接收人的金钱信息

 

    1. 确认发送人的余额大于发送金额

 

    1. 将发送金额从发送人减少,将发送金额增加到接收人

 

    将更新的信息写入

在一个事务中执行以上的一系列动作。

查询账户余额

    1. 获取所有用户信息

 

    1. 使用循环处理逐个提取用户信息

 

    从用户信息中获取余额,并显示在控制台上

建立环境

假设已经安装了执行所需操作的应用程序,我们可以使用Gradle来获取运行用的jar文件。

设定Scalar DB模式工具的路径。

在.bash_profile中添加到Schema Tools的路径设置
export SCHEMATOOL=/home/(自己环境的用户名)/scalardb/tools/schema

将设置更改生效。示例:$ source ~/.bash_profile

2. 设定样本项目目录配置

创建并移动到目录
$ mkdir ~/scalardb_sample
$ cd ~/scalardb_sample

执行gradle初始化命令
$ gradle init –type java-application

创建Gradle定义文件
$ 使用vi命令打开build.gradle文件

# mainClassNameの指定を変更(18行目)
# 変更前
mainClassName = 'App'
# 変更後
mainClassName = 'sample.emoney.ElectronicMoneyMain'
# dependenciesScalar DB定義を追加(22行目)
dependencies {
// This dependency is found on compile classpath of this component and consumers.
compile 'com.google.guava:guava:23.0'
compile group: 'com.scalar-labs', name: 'scalardb', version: '1.0.0'
// Use JUnit test framework
testCompile 'junit:junit:4.12'

通过gradle构建获取可执行的jar文件。

如果显示“构建成功”,那就表示OK。

完成

1. 创建模式文件
$ vi emoney.sdbql

REPLICATION FACTOR 1;
CREATE NAMESPACE emoney;
CREATE TRANSACTION TABLE emoney.account (
 group_id TEXT PARTITIONKEY,
 id TEXT CLUSTERINGKEY,
 balance INT,
);

使用Schema Tool,在Cassandra中创建模式。
$SCHEMATOOL/loader emoney.sdbql

使用cqlsh工具来确认数据库的架构

cqlsh> 查看所有keyspace,确认存在emoney

emoney system_auth coordinator system_traces
system_schema system system_distributed

确认表中存在account
cqlsh> 使用emoney数据库;
cqlsh:emoney> 查看所有表;

account

结束cqlsh。
cqlsh:emoney> 退出

我们将创建两个文件:一个包含构造函数和函数的类文件,另一个是用于接收参数并调用函数的执行类文件。

创建目录和Java文件
$ mkdir -p src/main/java/sample/emoney
$ cd src/main/java/sample/emoney
$ vi ElectronicMoney.java

创建文件夹和Java文件
$ mkdir -p src/main/java/sample/emoney
$ cd src/main/java/sample/emoney
$ vi ElectronicMoney.java

建立目录和Java文件
$ mkdir -p src/main/java/sample/emoney
$ cd src/main/java/sample/emoney
$ vi ElectronicMoney.java

package sample.emoney;

//インポート追加 
import com.google.inject.Guice; 
import com.google.inject.Injector; 
import com.scalar.database.config.DatabaseConfig; 
import com.scalar.database.service.StorageModule; 
import com.scalar.database.service.StorageService; 
import com.scalar.database.service.TransactionModule; 
import com.scalar.database.service.TransactionService; 

import java.io.File; 
import java.io.IOException; 

import com.scalar.database.api.DistributedTransaction; 
import com.scalar.database.api.Get; 
import com.scalar.database.api.Put; 
import com.scalar.database.api.Delete; 
import com.scalar.database.api.Result; 
import com.scalar.database.io.IntValue; 
import com.scalar.database.io.Key;
import com.scalar.database.io.TextValue; 
import com.scalar.database.exception.storage.ExecutionException; 
import com.scalar.database.exception.transaction.CommitException; 
import com.scalar.database.exception.transaction.CrudException; 
import com.scalar.database.exception.transaction.UnknownTransactionStatusException; 
import java.util.Optional;

import com.scalar.database.api.Scan; 
import com.scalar.database.api.Scanner;

public class ElectronicMoney {
  // クラス変数を定義
  private final String NAMESPACE = "emoney";
  private final String TABLE_NAME = "account";
  private final String ID = "id";
  private final String GROUP_ID = "group_id";
  private final String BALANCE = "balance";
  private final StorageService storageService;
  private final TransactionService transactionService;

  // コンストラクタを実装
  public ElectronicMoney() throws IOException {
   File prop_file = new File("/etc/scalar/database.properties");
   DatabaseConfig config = new DatabaseConfig(prop_file);
   Injector injector = Guice.createInjector(new StorageModule(config));
   storageService = injector.getInstance(StorageService.class);
   storageService.with(NAMESPACE, TABLE_NAME);
   injector = Guice.createInjector(new TransactionModule(config));
   transactionService = injector.getInstance(TransactionService.class);
   transactionService.with(NAMESPACE, TABLE_NAME);
  }

  public void charge(String groupId, String id, int amount) throws CrudException, CommitException, UnknownTransact ionStatusException {
   //トランザクション開始
   DistributedTransaction tx = transactionService.start();
   Key partitionKey = new Key(new TextValue(GROUP_ID, groupId));
   Key clusteringKey = new Key(new TextValue(ID, id));
   Get get = new Get(partitionKey, clusteringKey);
   Optional<Result> result = tx.get(get);
   int balance = amount;

   if (result.isPresent()) {
    int current = ((IntValue) result.get().getValue(BALANCE).get()).get();
    balance += current;
   }

   // 残高を更新
   Put put = new Put(partitionKey, clusteringKey).withValue(new IntValue(BALANCE, balance));
   tx.put(put);
   // トランザクションコミット
   tx.commit();
  }

  public void pay(String groupId, String fromId, String toId, int amount) throws CrudException,   CommitException, UnknownTransactionStatusException {
   // トランザクション開始
   DistributedTransaction tx = transactionService.start();
   // 送金元、送金先のアカウント情報を取得
   Key partitionKey = new Key(new TextValue(GROUP_ID, groupId));
   Key fromKey = new Key(new TextValue(ID, fromId));
   Key toKey = new Key(new TextValue(ID, toId));
   Get fromGet = new Get(partitionKey, fromKey);
   Get toGet = new Get(partitionKey, toKey);
   Optional<Result> fromResult = tx.get(fromGet);
   Optional<Result> toResult = tx.get(toGet);

   if (!fromResult.isPresent()) {
    throw new RuntimeException(fromId + " doesn't exist.");
   }
   if (!toResult.isPresent()) {
    throw new RuntimeException(toId + " doesn't exist.");
   }
   int newFromBalance = ((IntValue) (fromResult.get().getValue(BALANCE).get())).get() - amount;
   int newToBalance = ((IntValue) (toResult.get().getValue(BALANCE).get())).get() + amount;
   if (newFromBalance < 0) {
    throw new RuntimeException(fromId + " doesn't have enough balances.");
   }

   // 残高を更新
   Put fromPut = new Put(partitionKey, fromKey).withValue(new IntValue(BALANCE, newFromBalance));
   Put toPut = new Put(partitionKey, toKey).withValue(new IntValue(BALANCE, newToBalance));
   tx.put(fromPut);   tx.put(toPut);
   // トランザクションコミット
   tx.commit();
  }

  public void balances(String groupId) throws ExecutionException {
   Key partitionKey = new Key(new TextValue(GROUP_ID, groupId));
   Scan scan = new Scan(partitionKey);
   Scanner scanner = storageService.scan(scan);
   scanner.forEach(r -> {
    r.getValue(ID).ifPresent(v -> System.out.print(((TextValue) v).getString().get()));
    System.out.print(" : ");
    r.getValue(BALANCE).ifPresent(v -> System.out.println(((IntValue) v).get()));
   });
  }

  public void deleteUser(String groupId, String id) throws CrudException, CommitException, UnknownTransactionStatu sException {
   // トランザクション開始
   DistributedTransaction tx = transactionService.start();
   Key partitionKey = new Key(new TextValue(GROUP_ID, groupId));
   Key clusteringKey = new Key(new TextValue(ID, id));
   Get get = new Get(partitionKey, clusteringKey);
   Optional<Result> result = tx.get(get);
   if (!result.isPresent()) {
    tx.abort();
    return;
   }

    // 残高を更新
   Delete delete = new Delete(partitionKey, clusteringKey);
   tx.delete(delete);
   // トランザクションコミット
   tx.commit();
  }

  public void close() {
   storageService.close();
   transactionService.close();
  }
}

使用vi编辑器打开ElectronicMoneyMain.java文件

package sample.emoney; 

public class ElectronicMoneyMain {
 public static void main(String[] args) throws Exception {
  String action = null;
  int amount = 0;
  String group = null;
  String to = null;
  String from = null;

  for (int i = 0; i < args.length; ++i) {
   if ("-action".equals(args[i])) {
    action = args[++i];
   } else if ("-group".equals(args[i])) {
    group = args[++i];
   } else if ("-amount".equals(args[i])) {
    amount = Integer.parseInt(args[++i]);
   } else if ("-to".equals(args[i])) {
    to = args[++i];
   } else if ("-from".equals(args[i])) {
    from = args[++i];
   } else if ("-help".equals(args[i])) {
    printUsageAndExit();
   }
  }

 ElectronicMoney eMoney = new ElectronicMoney();
 if (action.equalsIgnoreCase("charge")) {
   eMoney.charge(group, to, amount);
  } else if (action.equalsIgnoreCase("pay")) {
   if (from == null) {
   printUsageAndExit();
   }
   eMoney.pay(group, from, to, amount);
  } else if (action.equalsIgnoreCase("balances")) {
   eMoney.balances(group);
  } else if (action.equalsIgnoreCase("delete")) {
   eMoney.deleteUser(group, to);
  }
  eMoney.close();
 }

 private static void printUsageAndExit() {
  System.err.println(
   "ElectronicMoneyMain -action charge/pay/balances/delete -group id -to id [-amount number (needed for charge/pay)] [-from id (needed for pay)]"
  );
  System.exit(1);
 }
}

执行

1. 充电

给用户1充值1000,请使用以下命令行参数运行Gradle:
$ gradle run –args=”-action 充值 -amount 1000 -group groupA -to user1″

以原生中文转述如下:
给用户2充值0
$ gradle run –args=”-action charge -amount 0 -group groupA -to user2″

image.png

2. 付款

用户1向用户2支付300元。
请输入以下命令执行:gradle run –args=”-action pay -amount 300 -group groupA -to user2 -from user1″。

image.png

3. 用户删除

删除用户1
$ gradle run –args=”-action delete -group groupA -to user1″

image.png

确认交易功能

为了确认交易功能正常运行,需要修改ElectronicMoney.java文件。

$ vi 电子货币.java

  public void pay(String groupId, String fromId, String toId, int amount) throws CrudException,   CommitException, UnknownTransactionStatusException {
   // トランザクション開始
   DistributedTransaction tx = transactionService.start();
   // 送金元、送金先のアカウント情報を取得
   Key partitionKey = new Key(new TextValue(GROUP_ID, groupId));
   Key fromKey = new Key(new TextValue(ID, fromId));
   Key toKey = new Key(new TextValue(ID, toId));
   Get fromGet = new Get(partitionKey, fromKey);
   Get toGet = new Get(partitionKey, toKey);
   Optional<Result> fromResult = tx.get(fromGet);
   Optional<Result> toResult = tx.get(toGet);

   if (!fromResult.isPresent()) {
    throw new RuntimeException(fromId + " doesn't exist.");
   }
   if (!toResult.isPresent()) {
    throw new RuntimeException(toId + " doesn't exist.");
   }
   int newFromBalance = ((IntValue) (fromResult.get().getValue(BALANCE).get())).get() - amount;
   int newToBalance = ((IntValue) (toResult.get().getValue(BALANCE).get())).get() + amount;
   if (newFromBalance < 0) {
    throw new RuntimeException(fromId + " doesn't have enough balances.");
   }

   // 残高を更新
   Put fromPut = new Put(partitionKey, fromKey).withValue(new IntValue(BALANCE, newFromBalance));
   // ----------------ここから追加行-----------------------
   // 実験用に必ずエラーをthrowする文の追加
   if (newFromBalance >= 0){
    throw new RuntimeException("test error.");
   }
   // ----------------ここまで追加行-----------------------
   // 送金先の残高は更新されない
   Put toPut = new Put(partitionKey, toKey).withValue(new IntValue(BALANCE, newToBalance));
   tx.put(fromPut);   tx.put(toPut);
   // トランザクションコミット
   tx.commit();
  }

使用者1充值1000。
$ gradle run –args=”-action charge -amount 1000 -group groupA -to user1″

以原生的中文方式表达上述句子(只提供一个选项):
用户2充值0元
$ gradle run –args=”-action 充值 -amount 0 -group 组A -to 用户2″

image.png

以上就是示例应用的执行情况。非常感谢您的阅读。

广告
将在 10 秒后关闭
bannerAds