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

ScalarDB Cluster .NET Client SDK での分散 SQL トランザクションをはじめよう

注記

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

ScalarDB Cluster .NET Client SDK は、ScalarDB Cluster の分散 SQL トランザクション機能をサポートします。SDK には、クラスター内での通信を容易にするためのトランザクションとマネージャーの抽象化が含まれています。

注記

次の例のように非同期メソッドを使用することをお勧めしますが、代わりに同期メソッドを使用することもできます。

分散非 SQL トランザクションの詳細については、ScalarDB Cluster .NET Client SDK での分散トランザクションをはじめようを参照してください。

SDK をインストールする

ScalarDB Cluster と同じメジャーバージョンとマイナーバージョンの SDK を .NET プロジェクトにインストールします。組み込みの NuGet パッケージマネージャーを使用してこれを行うことができます。<MAJOR>.<MINOR> を、使用しているバージョンに置き換えます。

dotnet add package ScalarDB.Client --version '<MAJOR>.<MINOR>.*'

設定ファイルを作成する

scalardb-options.json ファイルを作成し、次の内容を追加します。<HOSTNAME_OR_IP_ADDRESS> を FQDN または IP アドレスに、<PORT> をクラスターのポート番号 (デフォルトでは 60053) に置き換えます。

{
"ScalarDbOptions": {
"Address": "http://<HOSTNAME_OR_IP_ADDRESS>:<PORT>",
"HopLimit": 10
}
}

設定ファイルやクライアントを設定するその他の方法の詳細については、クライアント設定を参照してください。

トランザクションマネージャーを取得する

分散 SQL トランザクション用のトランザクションマネージャーオブジェクトを取得する必要があります。トランザクションマネージャーオブジェクトを取得するには、次のように TransactionFactory を使用します。

// Pass the path to the settings file created in the previous step.
var factory = TransactionFactory.Create("scalardb-options.json");

using var manager = factory.GetSqlTransactionManager();

SQL クエリを実行する

SQL ステートメントを実行するには、次のようにビルダーを使用して作成できる ISqlStatement オブジェクトが必要です。

using ScalarDB.Client.Builders.Sql;

// ...

var sqlStatement =
new SqlStatementBuilder()
.SetSql("SELECT * FROM order_service.statements WHERE item_id = :item_id")
.AddParam("item_id", 2)
.Build();

次のようにトランザクションマネージャーを使用して、単一の SQL ステートメントを直接実行できます。

var resultSet = await manager.ExecuteAsync(sqlStatement);

ExecuteAsync メソッドの結果には、クラスターから受信したレコードが含まれます。特定の列の値は、次の方法で取得できます。

foreach (var record in resultSet.Records)
{
// Getting an integer value from the "item_id" column.
// If it fails, an exception will be thrown.
var itemId = record.GetValue<int>("item_id");

// Trying to get a string value from the "order_id" column.
// If it fails, no exception will be thrown.
if (record.TryGetValue<string>("order_id", out var orderId))
Console.WriteLine($"order_id: {orderId}");

// Checking if the "count" column is null.
if (record.IsNull("count"))
Console.WriteLine("'count' is null");
}

GetValue<T> および TryGetValue<T> で使用する型の詳細については、ScalarDB 列型を .NET 型に変換する方法 を参照してください。

トランザクションで SQL クエリを実行する

1つのトランザクションの一部として複数の SQL ステートメントを実行するには、トランザクションオブジェクトが必要です。

次のようにトランザクションマネージャーを使用してトランザクションオブジェクトを作成できます。

var transaction = await manager.BeginAsync();

次のようにして、すでに開始されているトランザクションを再開することもできます。

var transaction = manager.Resume(transactionIdString);
注記

Resume メソッドはトランザクションオブジェクトを作成するだけなので、非同期バージョンはありません。このため、間違った ID を使用してトランザクションを再開する可能性があります。

読み取り専用トランザクションを開始する

トランザクション内で読み取り操作 (SELECT ステートメント) のみを実行する場合、次のように読み取り専用トランザクションを開始できます。

var transaction = await manager.BeginReadOnlyAsync();
注記

読み取り専用トランザクションは、書き込み操作が発行されないことを前提として、読み取り専用モードなしで開始された読み取りトランザクションよりも効率的に処理されます。そのため、読み取り専用トランザクション内で書き込み操作 (INSERTUPDATE、または DELETE ステートメント) を実行しようとするとエラーになります。

トランザクションには、トランザクションマネージャーと同じ ExecuteAsync メソッドがあります。このメソッドを使用して、SQL ステートメントを実行できます。

トランザクションをコミットする準備ができたら、次のようにトランザクションの CommitAsync メソッドを呼び出すことができます。

await transaction.CommitAsync();

トランザクションをロールバックするには、RollbackAsync メソッドを使用できます。

await transaction.RollbackAsync();

SQL ステートメントをバッチで実行する

ExecuteBatchAsync メソッドを使用すると、複数の SQL ステートメントを1回の RPC 呼び出しで実行でき、バッチ操作時のラウンドトリップのオーバーヘッドを削減できます。このメソッドは、トランザクションマネージャーとトランザクションオブジェクトの両方で使用できます。

トランザクションマネージャーを使用してバッチを実行する

次のように、トランザクションマネージャーを使用して SQL ステートメントのバッチを直接実行できます。

using ScalarDB.Client.Builders.Sql;

// ...

var statements = new[]
{
new SqlStatementBuilder()
.SetSql("INSERT INTO ns.statements (order_id, item_id, count) VALUES (:order_id, :item_id, :count)")
.AddParam("order_id", "1")
.AddParam("item_id", 1)
.AddParam("count", 5)
.Build(),
new SqlStatementBuilder()
.SetSql("INSERT INTO ns.statements (order_id, item_id, count) VALUES (:order_id, :item_id, :count)")
.AddParam("order_id", "2")
.AddParam("item_id", 2)
.AddParam("count", 10)
.Build()
};

var resultSets = await manager.ExecuteBatchAsync(statements);

トランザクション内でバッチを実行する

次のように、トランザクションの一部として SQL ステートメントのバッチを実行することもできます。

var transaction = await manager.BeginAsync();

var resultSets = await transaction.ExecuteBatchAsync(statements);

await transaction.CommitAsync();

結果は、入力ステートメントと同じ順序で IReadOnlyList<IResultSet> として返されます。SELECT ステートメントの場合、結果セットには取得されたレコードが含まれます。INSERTUPDATEDELETE ステートメントの場合、結果セットは空になります。

次の例では、複数の SELECT ステートメントをバッチで実行し、結果を処理します。

var selectStatements = new[]
{
new SqlStatementBuilder()
.SetSql("SELECT * FROM ns.statements WHERE order_id = :order_id")
.AddParam("order_id", "1")
.Build(),
new SqlStatementBuilder()
.SetSql("SELECT * FROM ns.statements WHERE order_id = :order_id")
.AddParam("order_id", "2")
.Build()
};

var resultSets = await transaction.ExecuteBatchAsync(selectStatements);

for (var i = 0; i < resultSets.Count; i++)
{
foreach (var record in resultSets[i].Records)
{
var itemId = record.GetValue<int>("item_id");
Console.WriteLine($"item_id: {itemId}");
}
}

位置パラメータを使用する

名前付きパラメータに加えて、次のように位置パラメータを使用することもできます。

var statements = new[]
{
new SqlStatementBuilder()
.SetSql("SELECT * FROM ns.statements WHERE order_id = ? AND item_id = ?")
.AddParam("1")
.AddParam(1)
.Build(),
new SqlStatementBuilder()
.SetSql("SELECT * FROM ns.statements WHERE order_id = ? AND item_id = ?")
.AddParam("2")
.AddParam(2)
.Build()
};

var resultSets = await transaction.ExecuteBatchAsync(statements);
注記

ExecuteBatchAsync に空のコレクションを渡した場合、RPC 呼び出しは行われず、空のリストが返されます。

メタデータを取得する

次のように、Metadata プロパティを使用して ScalarDB のメタデータを取得できます。

// namespaces, tables metadata
var namespaceNames = new List<string>();

await foreach (var ns in manager.Metadata.GetNamespacesAsync())
{
namespaceNames.Add(ns.Name);
Console.WriteLine($"Namespace: {ns.Name}");

await foreach (var tbl in ns.GetTablesAsync())
{
Console.WriteLine($" Table: {tbl.Name}");

Console.WriteLine($" Columns:");
foreach (var col in tbl.Columns)
Console.WriteLine($" {col.Name} [{col.DataType}]");

Console.WriteLine($" PartitionKey:");
foreach (var col in tbl.PartitionKey)
Console.WriteLine($" {col.Name}");

Console.WriteLine($" ClusteringKey:");
foreach (var col in tbl.ClusteringKey)
Console.WriteLine($" {col.Name} [{col.ClusteringOrder}]");

Console.WriteLine($" Indexes:");
foreach (var index in tbl.Indexes)
Console.WriteLine($" {index.ColumnName}");

Console.WriteLine();
}
}

// users metadata
await foreach (var user in manager.Metadata.GetUsersAsync())
{
Console.WriteLine($"User: {user.Name} [IsSuperuser: {user.IsSuperuser}]");

foreach (var nsName in namespaceNames)
{
Console.WriteLine($" Namespace: {nsName}");

Console.WriteLine($" Privileges:");
foreach (var privilege in await user.GetPrivilegesAsync(nsName))
Console.WriteLine($" {privilege}");
}

Console.WriteLine();
}
注記

IAsyncEnumerable<T> で LINQ メソッドを使用するには、System.Linq.Async パッケージをインストールします。