Cet article traite de la création d'un exemple d'application et exécutons l'exemple d'application de ScalarDB.
Cliquez ici pour la construction de l'environnement (https://qiita.com/XCAT_SE/private/07969c960fb776d78990)
Il existe deux composants d'exploitation pour ScalarDB: le composant Stockage et le composant Transaction.
Ce composant a les fonctions suivantes.
De plus, le rôle de la clé correspond ici à la clé de partition et à la clé de cluster de Cassandra, et plusieurs définitions peuvent être faites sous la forme de liste ou séparées par des virgules.
En outre, le composant de stockage ScalarDB fournit quatre fonctions pour les opérations CRUD.
Ce composant fournit des capacités de transaction sans maître en plus de la fonctionnalité du composant de stockage.
Pour utiliser la fonctionnalité de transaction, vous devez d'abord obtenir une instance TransactionService. Ensuite, après avoir exécuté les opérations Get, Put, Delete et Scan sur l'instance TransactionService, validez l'instance TransactionService et reflétez les détails de l'opération dans la base de données.
Vérifiez le fonctionnement de l'application réelle de ScalarDB avec l'exemple d'application.
Implémentez un exemple d'application avec ces fonctionnalités.
Diagramme d'image
KEYSPACE:emoney TABLE:account colonne ・ Group_id: ID de groupe (clé de partition) -Id: ID utilisateur (Clustering Key) ・ Solde: montant d'argent appartenant à l'utilisateur
Effectuez la série d'opérations ci-dessus en une seule transaction.
Effectuez la série d'opérations ci-dessus en une seule transaction.
En supposant que l'application requise pour l'opération a déjà été installée, utilisez gradle pour obtenir le fichier jar d'exécution.
-Ajoutez le paramètre de chemin aux outils de schéma à .bash_profile ʻExport SCHEMATOOL = / home / (nom d'utilisateur de votre environnement) / scalarb / tools / schema`
・ Refléter le changement de réglage
$ source ~/.bash_profile
・ Créer et déplacer un répertoire
$ mkdir ~/scalardb_sample
$ cd ~/scalardb_sample
-Exécuter la commande d'initialisation gradle
$ gradle init --type java-application
$ vi build.gradle
build.gradle
#Modifier la spécification de mainClassName(18e ligne)
#Changer avant
mainClassName = 'App'
#Après le changement
mainClassName = 'sample.emoney.ElectronicMoneyMain'
#Ajout de la définition de base de données scalaire aux dépendances(Ligne 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 build
OK si BUILD SUCCESS FUL
s'affiche
$ vi emoney.sdbql
emoney.sdbql
REPLICATION FACTOR 1;
CREATE NAMESPACE emoney;
CREATE TRANSACTION TABLE emoney.account (
group_id TEXT PARTITIONKEY,
id TEXT CLUSTERINGKEY,
balance INT,
);
$ $SCHEMATOOL/loader emoney.sdbql
Vérifiez le schéma avec cqlsh
$ cqlsh
Assurez-vous qu'il y a de l'argent dans l'espace de clé
cqlsh> DESCRIBE KEYSPACES ;
Résultat d'exécution
emoney system_auth coordinator system_traces
system_schema system system_distributed
Assurez-vous qu'il y a un compte dans le tableau
cqlsh> use emoney;
cqlsh:emoney> DESCRIBE TABLES ;
Résultat d'exécution
account
Quitter cqlsh
cqlsh:emoney> exit
Créez-en deux, un fichier de classe qui décrit le constructeur et la fonction, et un fichier de classe d'exécution qui reçoit des arguments et appelle la fonction.
Créer un répertoire et un fichier java
$ mkdir -p src/main/java/sample/emoney
$ cd src/main/java/sample/emoney
$ vi ElectronicMoney.java
ElectronicMoney.java
package sample.emoney;
//Ajouter une importation
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 {
//Définir les variables de classe
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;
//Implémenter le constructeur
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 {
//Début de la transaction
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;
}
//Mettre à jour le solde
Put put = new Put(partitionKey, clusteringKey).withValue(new IntValue(BALANCE, balance));
tx.put(put);
//Engagement de transaction
tx.commit();
}
public void pay(String groupId, String fromId, String toId, int amount) throws CrudException, CommitException, UnknownTransactionStatusException {
//Début de la transaction
DistributedTransaction tx = transactionService.start();
//Obtenir les informations de compte de l'expéditeur et du destinataire
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.");
}
//Mettre à jour le solde
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);
//Engagement de transaction
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 {
//Début de la transaction
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;
}
//Mettre à jour le solde
Delete delete = new Delete(partitionKey, clusteringKey);
tx.delete(delete);
//Engagement de transaction
tx.commit();
}
public void close() {
storageService.close();
transactionService.close();
}
}
$ vi ElectronicMoneyMain.java
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);
}
}
1000 frais à l'utilisateur1
$ gradle run --args="-action charge -amount 1000 -group groupA -to user1"
0 frais à l'utilisateur2
$ gradle run --args="-action charge -amount 0 -group groupA -to user2"
Vérifiez le solde de l'utilisateur1 et de l'utilisateur2
$ gradle run --args="-action balances -group groupA"
300 paiements de l'utilisateur1 à l'utilisateur2
$ gradle run --args="-action pay -amount 300 -group groupA -to user2 -from user1"
Vérifiez le solde de l'utilisateur1 et de l'utilisateur2
$ gradle run --args="-action balances -group groupA"
Supprimer l'utilisateur1
$ gradle run --args="-action delete -group groupA -to user1"
Vérifiez le solde de l'utilisateur2 et confirmez que l'utilisateur1 a été supprimé
$ gradle run --args="-action balances -group groupA"
Modifiez ʻElectronicMoney.java` pour vous assurer que la fonction de transaction fonctionne.
$ vi ElectronicMoney.java
ElectronicMoney.java(fonction de paye,Près de la ligne 101)
public void pay(String groupId, String fromId, String toId, int amount) throws CrudException, CommitException, UnknownTransactionStatusException {
//Début de la transaction
DistributedTransaction tx = transactionService.start();
//Obtenir les informations de compte de l'expéditeur et du destinataire
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.");
}
//Mettre à jour le solde
Put fromPut = new Put(partitionKey, fromKey).withValue(new IntValue(BALANCE, newFromBalance));
// ----------------Lignes supplémentaires d'ici-----------------------
//Ajouter une instruction qui génère toujours une erreur pour l'expérimentation
if (newFromBalance >= 0){
throw new RuntimeException("test error.");
}
// ----------------Lignes supplémentaires jusqu'à ici-----------------------
//Le solde du destinataire n'est pas mis à jour
Put toPut = new Put(partitionKey, toKey).withValue(new IntValue(BALANCE, newToBalance));
tx.put(fromPut); tx.put(toPut);
//Engagement de transaction
tx.commit();
}
1000 frais à l'utilisateur1
$ gradle run --args="-action charge -amount 1000 -group groupA -to user1"
0 frais à l'utilisateur2
$ gradle run --args="-action charge -amount 0 -group groupA -to user2"
Vérifiez le solde avant l'exécution
gradle run --args="-action balances -group groupA"
Essayez d'exécuter le processus de remise
gradle run --args="-action pay -amount 300 -group groupA -to user2 -from user1"
gradle run --args="-action balances -group groupA"
Puisque la fonction de transaction fonctionne, le solde de l'expéditeur n'est pas réduit et le même solde qu'avant l'exécution est affiché.C'est tout pour exécuter l'exemple d'application. Merci pour la lecture.
Recommended Posts