トランザクション(Transaction):複数のSQL操作をアトミックに実行し、すべて成功すればコミット(Commit)、どこかで失敗すれば全部ロールバック(Rollback)する仕組みで、ACID特性を満たします。
.NET Framework/.NET では SqlTransaction(SQL Server専用)を使って実装します。
処理のポイント:
- データベース接続を開く
conn.Open()- 接続からトランザクションを開始
conn.BeginTransaction()- トランザクションオブジェクトを
SqlCommand.Transactionに紐付け- 複数のSQLを一括実行
- 例外なし:
tx.Commit();例外発生時:tx.Rollback()
サンプルコード
元のコードにはcatchによるロールバック処理がないため、完全な動作可能版を示します:
public static int ExecuteSqlTran(List<string> SQLStringList)
{
using (SqlConnection conn = new SqlConnection(connectionString))
{
conn.Open();
SqlCommand cmd = new SqlCommand();
cmd.Connection = conn;
SqlTransaction tx = conn.BeginTransaction();
cmd.Transaction = tx;
try
{
int count = 0;
for (int n = 0; n < SQLStringList.Count; n++)
{
string strsql = SQLStringList[n];
if (strsql.Trim().Length > 1)
{
cmd.CommandText = strsql;
count += cmd.ExecuteNonQuery();
}
}
tx.Commit(); // 全て成功したらコミット
return count;
}
catch (Exception ex)
{
tx.Rollback(); // 1つでも失敗したら全てロールバック
throw ex; // 上位側へ例外を再スローして失敗を通知
}
}
}Code language: C# (cs)
このコードはSQL文字列を直接連結しておりSQLインジェクションの危険があります。トランザクションの仕組み理解用として使用し、実際の開発ではパラメータ化クエリを優先してください。
パラメータを使用したトランザクション例
SqlParameterを利用してインジェクションを防ぎつつループでデータを挿入します。重要なポイント:
- ループの末尾で
sqlCom.Parameters.Clear()を呼び出し、前回のパラメータを削除してエラーを回避する - 同一の
SqlCommandインスタンスを再利用し、CommandTextとパラメータだけ更新する
SqlCommand sqlCom = new SqlCommand();
sqlCom.Connection = conn;
SqlTransaction st = conn.BeginTransaction();
sqlCom.Transaction = st;
int res = 0;
try
{
for (int i = 0; i < 10; i++)
{
sqlCom.CommandText = "INSERT INTO [dbo].[Article]([Title])VALUES(@Title)";
SqlParameter param = new SqlParameter("@Title", SqlDbType.NVarChar, 250);
param.Value = i + "新しいタイトル" + DateTime.Now;
sqlCom.Parameters.Add(param);
res += sqlCom.ExecuteNonQuery();
sqlCom.Parameters.Clear(); // 次ループのためパラメータをクリア
}
st.Commit();
}
catch (Exception)
{
st.Rollback(); // 例外発生時は全操作を取り消し
}Code language: C# (cs)
1. 必ず守るべきルール
BeginTransaction()は接続Openの後で実行するSqlCommandにはTransactionプロパティを設定しないと例外が発生しますCommit()/Rollback()実行後はトランザクションが終了するため、重複呼び出しはできません
その他
- .NET Core/.NET 5+ では
usingによりSqlTransactionを自動解放することを推奨 - 大量データを一括処理する場面では
SqlBulkCopyを検討してください。ループでExecuteNonQueryを回すより高速です - データベースをまたぐトランザクションにはSqlTransactionは対応していません。分散トランザクションの
TransactionScopeを使用します
SqlTransaction データベーストランザクション
Previous: ExecuteNonQuery
Next: SqlDataReader