Транзакция в C#
Транзакция собирает несколько команд в одно
целое. Между BeginTransaction и
Commit другие соединения не видят
перевод наполовину: либо оба счёта уже
обновлены, либо ещё ни один.
Пока Commit не вызван, весь набор можно
отменить. В примере перевод фиксируют: со счёта
"cash" списывают 30, на
"reserve" прибавляют те же 30.
Пакет провайдера в файле проекта:
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>net10.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Microsoft.Data.Sqlite" Version="10.0.14" />
</ItemGroup>
</Project>
Создадим счета и выполним парный перевод в одной транзакции:
using Microsoft.Data.Sqlite;
using SqliteConnection db = new("Data Source=:memory:");
db.Open();
using (SqliteCommand setup = db.CreateCommand())
{
setup.CommandText =
"CREATE TABLE IF NOT EXISTS accounts (name TEXT PRIMARY KEY, balance INT NOT NULL);"
+ "INSERT INTO accounts VALUES ('cash',100),('reserve',0);";
setup.ExecuteNonQuery();
}
using SqliteTransaction tx = db.BeginTransaction();
using (SqliteCommand move = db.CreateCommand())
{
move.Transaction = tx;
move.CommandText =
"UPDATE accounts SET balance = balance - 30 WHERE name = 'cash';"
+ "UPDATE accounts SET balance = balance + 30 WHERE name = 'reserve';";
move.ExecuteNonQuery();
}
tx.Commit();
using SqliteCommand q = db.CreateCommand();
q.CommandText = "SELECT balance FROM accounts WHERE name = 'reserve'";
Console.WriteLine(q.ExecuteScalar());
В памяти заведите таблицу "wallets"
с колонками "owner" и "cents".
У "Alice" 500, у "Bob"
0. В одной транзакции переведите
120 от "Alice" к "Bob"
и выведите баланс Bob.