データベース千夜一夜第26回

トランザクションの管理(2)~プログラミングとトランザクション管理 長谷川裕行
有限会社 手國堂

トランザクション管理のサンプル

ここで、レコードの削除を取り消す例を紹介しておきましょう。本コラムの第14回「プログラミングとSQL(2)~レコードの削除処理」で紹介した、商品マスターからの商品検索と削除処理に手を加え、[削除]ボタンをクリックしてDELETE命令で商品のレコードを削除した後、その処理を取り消すこともできる──という仕様に変更したものです。



【注意】

本コラムのサンプルでは、MSDEを使った個人的なデスクトップ環境でデータベースを扱うことを前提にしているため、接続先のSQL Serverは“localhost”としています。

ネットワーク上のリモート・コンピュータで稼働しているSQL Serverに接続する場合には、以下の接続文字列の最後の引数“server=localhost”の“localhost”の箇所を適宜サーバー名に書き換えてください(ここで言う「サーバー名」とはコンピュータの識別名ではなく、SQL Serverに割り当てた識別名です)。
objConnect.ConnectionString = _
  "Persist Security Info=False;
   Integrated Security=SSPI;database=db1001ya;
   server=localhost"
          ~~~~~~~~~
              ↑この箇所を書き換える



- 削除後に取り消せる -

アプリケーションの動作は次のようになります(画面1~画面5)。

(1)テキストボックスに商品IDを入力して[検索]ボタンをクリック

(2)該当する商品の品名が表示されるので[削除]ボタンをクリック

(3)削除の確認ダイアログが表示されるので[はい]をクリック
 この段階でトランザクション管理を有効にするためBEGIN TRANSACTION命令を発行し、続けてDELETE命令で対象レコードを削除します。

(4)削除の再確認ダイアログが表示されるので[いいえ]をクリック
 ここで[はい]をクリックするとCOMMIT TRANSACTION命令で処理が確定されてレコードは削除されます。[いいえ]をクリックすればROLLBACK TRASACTION命令が発行され、先のDELETE命令による削除は取り消されます。

(5)削除が取り消された旨のメッセージが表示される
  上記(4)の段階で[いいえ]をクリックすると、削除が取り消された旨のメッセージを表示します。Enterprise Managerでテーブル「商品_dmy」を開いて確認してください。

なお、操作の対象とするテーブルには、「商品_mr」と同じ内容を記録した「商品_dmy」を使っています。また、第14回の例では商品名と共に在庫数も表示するようにしていましたが、今回は「レコードの削除と取り消し処理」だけに絞って説明するため、在庫数の表示処理(テーブル「在庫_mr」との関連付け)は省略してあります。

画面1:テキストボックスに削除したい商品の商品IDを入力する
画面1:テキストボックスに削除したい商品の商品IDを入力する
画面2:[検索]ボタンをクリックすると該当する商品名が表示される
画面2:[検索]ボタンをクリックすると該当する商品名が表示される

画面3:削除の確認ダイアログが表示される(ここでは[はい]をクリック)
画面3:削除の確認ダイアログが表示される
(ここでは[はい]をクリック)

画面4:SQL発行後に削除の再確認ダイアログが表示される([いいえ]をクリック)
画面4:SQL発行後に削除の再確認ダイアログが表示される
([いいえ]をクリック)

画面5:削除が取り消される
画面5:削除が取り消される


- Ifで確定/取消に分岐 -

上記処理の中心となる、削除と取り消し部分のソースを掲げておきます(アプリケーション全体については、サンプルのプロジェクトを開いてフォームのデザインとソースを確認してください)。

この処理は、[削除]ボタンをクリックしたときのイベントプロシージャ“btnDelete_Click”に割り当てています。

ソース中のアミをかけた箇所(a)(c)が、トランザクション管理でレコード削除の確定と取り消しを制御している部分です。BEGIN TRANSACTIONなどの命令も通常のSQL命令と同じくSqlCommandオブジェクトのCommandTextに文字列として設定し、ExecuteNonQueryメソッドでそれを実行します。

(a)BEGIN TRANSACTION命令を発行してトランザクションの管理を開始

その後、
     objCommand.CommandText = strSql
     If objCommand.ExecuteNonQuery >= 1 Then     ' 削除実行
       If MsgBox("本当に削除しますか?", _
          MsgBoxStyle.Question.YesNo, "削除の再確認") _
          = MsgBoxResult.Yes Then
として実際にDELETE命令を発行してレコードを削除します。続けてユーザーに削除の確認を求め、[はい]がクリックされたら(b)へ、[いいえ]がクリックされたら(c)へ制御を移行します。

(b)COMMIT TRANSACTION命令を発行して削除を確定します

(c)
ROLLBACK TRANSACTION命令を発行して先のDELETE命令を取り消します

リスト1:レコードの削除と確定/取り消し処理のソース
 ' ------------------------------------------------

 ' 削除処理(対象レコードはグローバル変数から取得)

 ' ------------------------------------------------

 Private Sub btnDelete_Click _

  (ByVal sender As System.Object, ByVal e As System.EventArgs) _
  Handles btnDelete.Click
   Dim objConnect As New SqlConnection
   Dim objCommand As New SqlCommand
   Dim strMessage As String
   Dim strSql As String
   
   ' 削除用の接続文字列を設定
   strSql = _
     "DELETE 商品_dmy WHERE 商品ID = " & strTargetId

   ' ユーザー宛の確認メッセージ
   strMessage = "商品ID:" & strTargetId & vbCrLf & _
                "品名:" & strTargetName & vbCrLf & _
                "を削除します。よろしいですか?"

   ' 未検索時には処理を行わない
   If (strTargetId = "") Or (strTargetName = "") Then
     MsgBox("商品が特定されていません。", _
       MsgBoxStyle.OKOnly, "商品エラー")
     Exit Sub
   End If

   ' ユーザーに削除の確認を求める
   If MsgBox(strMessage, MsgBoxStyle.YesNo, "削除の確認") _
     = MsgBoxResult.No Then
     Exit Sub
   End If

   Try
     ' 接続文字列の設定
     objConnect.ConnectionString = _
       "Persist Security Info=False;Integrated Security=SSPI;" & _
"database=db1001ya;server=localhost" ' コネクションの設定 objCommand.Connection = objConnect ' 接続を開く objConnect.Open() ' トランザクション開始 ------------------------------(a) objCommand.CommandText = "BEGIN TRANSACTION" objCommand.ExecuteNonQuery() ' SQLの設定 objCommand.CommandText = strSql If objCommand.ExecuteNonQuery >= 1 Then ' 削除実行 If MsgBox("本当に削除しますか?", _ MsgBoxStyle.Question.YesNo, "削除の再確認") _ = MsgBoxResult.Yes Then ' コミット(削除を確定) ------------------------(b) objCommand.CommandText = "COMMIT TRANSACTION" objCommand.ExecuteNonQuery() MsgBox("削除しました。", MsgBoxStyle.OKOnly, "削除完了") Else ' ロールバック(削除を取消) --------------(c) objCommand.CommandText = "ROLLBACK TRANSACTION" objCommand.ExecuteNonQuery() MsgBox("削除を取り消しました。", MsgBoxStyle.OKOnly, "削除取消") End If InitForm() ' 再実行に備えてテキストボックスとグローバル変数を初期化 Else ' 検索失敗 MsgBox("該当する商品が見つかりません。", _ MsgBoxStyle.OKOnly, "検索エラー") Exit Sub End If Catch objExcept As Exception ' 例外処理 MsgBox(objExcept.ToString, MsgBoxStyle.OKOnly, "DBエラー") Finally ' 接続を閉じる If Not objConnect Is Nothing Then objConnect.Close() End If End Try End Sub


- 変数を使う方が合理的 -

サンプルではBEGIN、COMMIT、ROLLBACKの各命令の実行箇所を分かりやすくするため、実行の都度CommandTextに"BEGIN TRANSACTION"などのSQL文字列を代入していますが、実際のプログラミングでは処理の冒頭でString型の変数を宣言し、以下のように各SQL文を予め代入しておく方が合理的です。

なお、この方法で記述した“btnDelete_Click”プロシージャのソースは、サンプルの“ex01source.txt”に記載してあります。

・SQLを保存するString型変数を宣言
  Dim strBeginTran As String
  Dim strCommit As String
  Dim strRollBack As String

・各変数にSQL文字列を代入
  strBeginTran = "BEGIN TRANSACTION"
  strCommit = "COMMIT TRANSACTION"
  strRollBack = "ROLLBACK TRANSACTION"

・CommandTextに変数を代入してSQLを発行

トランザクション管理の開始
  objCommand.CommandText = strBeginTran
  objCommand.ExecuteNonQuery()

トランザクションの確定
  objCommand.CommandText = strCommit
  objCommand.ExecuteNonQuery()

トランザクションの取消
  objCommand.CommandText = strRollBack
  objCommand.ExecuteNonQuery()


トップページ
明示的なトランザクション管理
トランザクション管理のサンプル
削除後に取り消せる
Ifで確定/取消に分岐
変数を使う方が合理的
複雑なトランザクション管理
あとがき
Copyright © MESCIUS inc. All rights reserved.