記事ディレクトリ
序文
トランザクションとは、すべてが正常に実行されるか、またはまったく実行されない一連の操作を指します。部分的な実行は成功、部分的な実行は失敗します。トランザクションの役割は、データの一貫性を確保し、複数の操作の実行結果がアトミックであることを保証し、データの整合性と正確性を保証することです。
分散トランザクションとは、分散システム内の複数のノードまたは複数のデータベースにわたるトランザクションを指します。分散環境では、データが複数のノードに分散しているため、分散トランザクション全体の一貫性、つまりすべてのノードが正常に実行されるか、まったく実行されないかのいずれかを保証する必要があります。したがって、分散トランザクションの重要性は、データの一貫性、信頼性、完全性を確保し、データの損失と重複を防止し、分散システムの高可用性と高性能を実現することです。
分散トランザクションを実装するには、2 フェーズ コミット プロトコル、3 フェーズ コミット プロトコル、補償トランザクションなど、さまざまな方法があります。このうち、2フェーズコミットプロトコルは最も古典的な実装方式であり、プリコミット、コミット、ロールバックの3段階で分散トランザクション全体の整合性を確保しますが、パフォーマンスの低下や、スケーラビリティ。したがって、実際の分散システムでは、特定のシナリオや要件に応じて、適切な分散トランザクションの実装方法を選択する必要があります。
1. EF問題と環境問題
1.EF事務
EF では、BeginTransaction はトランザクションを開始するメソッドです。これにより、トランザクション スコープ内で複数の操作を実行し、これらの操作がすべて正常に実行されるか、すべてロールバックされることを確認できます。
BeginTransaction メソッドを使用する手順は次のとおりです。
- EF のデータ コンテキストである DbContext オブジェクトを作成します。
- トランザクションを表す DbContextTransaction オブジェクトをインスタンス化します。
- DbContext の Database.BeginTransaction() メソッドを呼び出し、トランザクションの開始を示す DbContextTransaction オブジェクトを返します。
- トランザクションのサポートを必要とするトランザクション スコープ内で操作を実行します。
- DbContextTransaction の Commit() メソッドを呼び出してトランザクションをコミットするか、Rollback() メソッドを呼び出してトランザクションをロールバックします。
以下は、BeginTransaction メソッドを使用してトランザクションを開始する例です。
using (var db = new MyDbContext())
{
using (var transaction = db.Database.BeginTransaction())
{
try
{
//在事务范围内执行需要支持事务的操作,比如:
db.Customers.Add(new Customer {
Name = "Alice" });
db.Orders.Add(new Order {
CustomerId = 1, TotalPrice = 100 });
db.SaveChanges();
//提交事务
transaction.Commit();
}
catch (Exception ex)
{
//发生异常时回滚事务
transaction.Rollback();
Console.WriteLine("Error: " + ex.Message);
}
}
}
この例では、最初に MyDbContext オブジェクトを作成し、次に BeginTransaction メソッドを使用してトランザクションを開始し、最後に Commit メソッドを呼び出してトランザクションをコミットするか、例外が発生したときに Rollback メソッドを呼び出してトランザクションをロールバックします。
BeginTransaction メソッドを使用してトランザクションを開始する場合は、操作の完了後に必ず Commit メソッドを呼び出してトランザクションを送信するか、Rollback メソッドを呼び出してトランザクションをロールバックするようにしてください。そうしないと、データの不整合が発生します。
2. 環境問題
2.1 トランザクションスコープ
System.Transactions は、C# で環境トランザクションを実装するために使用される名前空間です。環境トランザクション (分散トランザクションとも呼ばれる) は、複数のデータ ソース (複数のデータベース、メッセージ キューなど) が関与するトランザクションであり、複数のデータ ソース間での一貫性が必要です。System.Transactions は、この種のトランザクションを処理するための、シンプルで信頼性が高く、スケーラブルな方法を提供します。
System.Transactions は、.NET Framwork に基づくトランザクション処理メカニズムであり、トランザクションを管理するための TransactionScope クラスを提供し、ADO.NET、Message Queue などの複数のデータ ソースと互換性があります。
System.Transactions を使用する手順は次のとおりです。
- 環境トランザクションを表す TransactionScope オブジェクトを作成します。
- 環境トランザクションをサポートする必要がある TransactionScope オブジェクトのスコープ内で操作を実行します。
- TransactionScope オブジェクトの Complete() メソッドを呼び出してトランザクションをコミットするか、Complete メソッドを呼び出さずにコードで TransactionScope コード ブロックを終了します。このとき、トランザクションは自動的にロールバックされます。
以下は、TransactionScope オブジェクトを使用してトランザクションを管理する例です。
using (var scope = new TransactionScope(
TransactionScopeOption.Required,
new TransactionOptions {
IsolationLevel = IsolationLevel.ReadCommitted }))
{
using var connection = new SqlConnection(connectionString);
connection.Open();
try
{
// Run raw ADO.NET command in the transaction
var command = connection.CreateCommand();
command.CommandText = "DELETE FROM dbo.Blogs";
command.ExecuteNonQuery();
// Run an EF Core command in the transaction
var options = new DbContextOptionsBuilder<BloggingContext>()
.UseSqlServer(connection)
.Options;
using (var context = new BloggingContext(options))
{
context.Blogs.Add(new Blog {
Url = "http://blogs.msdn.com/dotnet" });
context.SaveChanges();
}
// Commit transaction if all commands succeed, transaction will auto-rollback
// when disposed if either commands fails
scope.Complete();
}
catch (Exception)
{
// TODO: Handle failure
}
}
この例では、TransactionScope オブジェクトを使用して環境トランザクションを管理し、次に TransactionScope コード ブロック内の 2 つの SqlConnection オブジェクトによって表されるデータ ソースに対して操作を実行し、最後に Complete メソッドを呼び出してトランザクションをコミットします。
TransactionScope オブジェクトを使用してトランザクションを管理する場合は、トランザクション スコープ内で実行される操作がトランザクションをサポートしていることを確認する必要があります。そうしないと、データの不整合が発生する可能性があります。さらに、TransactionScope オブジェクトを使用してトランザクションを管理する場合は、データ ソースが分散トランザクションをサポートしていることを確認する必要もあります。サポートされていない場合は、NotSupportedException がスローされます。
2.2 コミット可能なトランザクション
CommittableTransaction は、.net Framework によって提供されるトランザクション メカニズムであり、トランザクション操作中に複数のリソース (データベースやファイル システムなど) の一貫性を制御するために使用できます。
CommittableTransaction は、System.Transactions 名前空間を通じて提供され、次の重要なメソッドを提供します。
- 開始: 新しい CommittableTransaction オブジェクトを作成します。
- コミット: トランザクションを送信して有効にします。
- ロールバック: トランザクションをロールバックし、前の操作をキャンセルします。
- EnlistResource: トランザクションにリソースを追加します。
CommittableTransaction を使用する場合は、通常、次の手順に従う必要があります。
- CommittableTransaction オブジェクトを作成します。
- トランザクションに参加する必要があるリソースをトランザクションに追加します。
- 操作 (データベースへの更新やファイル システムへの書き込みなど) を実行します。
- 操作が成功した場合は、Commit メソッドを呼び出してトランザクションをコミットします。
- 操作が失敗した場合は、Rollback メソッドを呼び出してトランザクションをロールバックします。
以下は CommittableTransaction を使用したサンプル コードです。
using (var transaction = new CommittableTransaction(
new TransactionOptions {
IsolationLevel = IsolationLevel.ReadCommitted }))
{
var connection = new SqlConnection(connectionString);
try
{
var options = new DbContextOptionsBuilder<BloggingContext>()
.UseSqlServer(connection)
.Options;
using (var context = new BloggingContext(options))
{
context.Database.OpenConnection();
context.Database.EnlistTransaction(transaction);
// Run raw ADO.NET command in the transaction
var command = connection.CreateCommand();
command.CommandText = "DELETE FROM dbo.Blogs";
command.ExecuteNonQuery();
// Run an EF Core command in the transaction
context.Blogs.Add(new Blog {
Url = "http://blogs.msdn.com/dotnet" });
context.SaveChanges();
context.Database.CloseConnection();
}
// Commit transaction if all commands succeed, transaction will auto-rollback
// when disposed if either commands fails
transaction.Commit();
}
catch (Exception)
{
// TODO: Handle failure
}
}
上記の例では、CommittableTransaction を使用してデータベース更新操作のトランザクションを制御します。操作が成功した場合はトランザクションをコミットし、失敗した場合はトランザクションをロールバックします。
2.3 CommittableTransaction と TransactionScope の違い
CommittableTransaction と TransactionScope はどちらも、トランザクションを管理するために .NET Framework で提供されるクラスであり、これらの主な違いは、使用方法とトランザクション管理の粒度にあります。
CommittableTransaction は、コードで明示的に作成および管理されるトランザクション オブジェクトであり、開発者は、管理する必要があるリソースと、トランザクションをいつコミットまたはロールバックするかを手動で指定する必要があります。通常、CommittableTransaction はコードでカスタム トランザクション管理ロジックを実行するときに使用されます。
TransactionScope は、複数のトランザクション リソースのトランザクション操作を自動的に管理できる高レベルのトランザクション管理クラスです。TransactionScope を使用する場合、開発者は、同じトランザクションで実行する必要があるコード ブロックを TransactionScope オブジェクトに配置するだけでよく、トランザクションの管理と送信またはロールバックは、TransactionScope オブジェクト インスタンスによって自動的に完了します。
具体的には、CommittableTransaction はコード内で明示的なトランザクション管理を必要とし、トランザクションが管理する必要があるリソースとトランザクションをいつコミットまたはロールバックするかを手動で指定する必要があるのに対し、TransactionScope は開発者にリソースとトランザクション操作の自動管理を提供します。管理。
TransactionScope も内部で CommittableTransaction を使用してトランザクション管理を実装しますが、より便利で使いやすくするためにカプセル化されていることに注意してください。
2.4 System.Transactions の制限事項
System.Transactions には次の制限があります。
-
分散トランザクションをサポートするデータベースでのみ使用できます。分散トランザクションをサポートしていないデータベースは、System.Transactions を介してトランザクション処理を実行できません。
-
分散トランザクションでは、複数の参加者の操作を調整する必要があるため、パフォーマンスの問題が発生する可能性があります。
-
System.Transactions はデータベース トランザクションとメッセージ キュー トランザクションのみを処理でき、ファイル システム トランザクションなどの他の種類のトランザクション処理には使用できません。
-
分散トランザクションでは、参加者の 1 つが失敗すると、トランザクション全体が失敗するか、ロールバックが必要になる場合があります。これにより、データの損失やアプリケーションの異常が発生する可能性があります。
-
場合によっては、System.Transactions の制限により、分散トランザクション処理コードを手動で記述する必要がある場合があります。これにより、作業が増え、複雑さが増す可能性があります。
-
.NET Core 2.1 の時点では、System.Transactions 実装には分散トランザクションのサポートが含まれていないため、TransactionScope または CommittableTransaction を使用して複数のリソース マネージャー間でトランザクションを調整することはできません。