- PR -

SQLparameterとトランザクション

投稿者投稿内容
Taito
常連さん
会議室デビュー日: 2005/07/21
投稿数: 43
投稿日時: 2006-02-17 11:34
先日、「INSERTのVALUESの値に閉じていない括弧が存在する場合」
という件名で質問させていただき、その際にSQLparameterで実行する
やり方を教えていただきました。

今までのプログラムを変更しているのですが、
トランザクション処理を使用しているプログラムがエラーになりました。

原因を色々調べたのですが、よく分からず困っております。
エラーを検索してもほとんど情報が出てきませんでした。

処理はこのように行っており
1.トランザクション開始
2.SQLパラメータを使用した追加クエリ
3.エラーがなければコミット
4.エラーがあればロールバック

3のコミット時にエラーが出ます。エラーの内容はこれです。
EXECUTE 後のトランザクション数は、 COMMIT TRAN または ROLLBACK TRAN ステートメントに間違いがあることを示しています。以前の数 = 1、現在の数 = 0 です。

SQLパラメータを使用しない場合は問題なく実行できます。

組合わせで使用ができないということはあるのでしょうか?

何か分かる方がいらっしゃいましたらアドバイスよろしくお願い致します。
burton999
ぬし
会議室デビュー日: 2003/10/06
投稿数: 898
お住まい・勤務地: 東京
投稿日時: 2006-02-17 12:49
SqlParameterを使用しても問題なくトランザクション処理は行えます。
どのようなコードを書いたのか最低限のコードを書いてもらえると回答しやすいのですが。。。
Taito
常連さん
会議室デビュー日: 2005/07/21
投稿数: 43
投稿日時: 2006-02-17 13:30
引用:

burton999さんの書き込み (2006-02-17 12:49) より:
SqlParameterを使用しても問題なくトランザクション処理は行えます。
どのようなコードを書いたのか最低限のコードを書いてもらえると回答しやすいのですが。。。



burton999さん、できるんですね。
ソースは要約したらこんな感じです。よろしくお願いします。

Public Class F_buhintori
  Dim CN As New SqlClient.SqlConnection
  Dim CMD As New SqlClient.SqlCommand
  Dim DR As SqlClient.SqlDataReader
  Dim ERRORECODE As Integer
  Dim ERROREMSG As String

Private Sub btn_受注取込_Click
  CN.ConnectionString = "Server=" & DB_SERVER & ";Initial Catalog=" & DB_CATALOG & ";User ID=" & DB_USER & ";Password=" & DB_PASSWORD & ";"
  CN.Open()
  CMD.Connection = CN

  begintransaction()
  make_item()

  If ERRORECODE = 0 Then
    committransaction()
  Else
    rollbacktransaction()
  End If

  If ERRORECODE = 0 Then
    MsgBox("取込が終了しました")
  Else
    MsgBox(ERROREMSG)
  End If
End Sub

Function make_item()
  CMD.CommandText = ="INSERT INTO TEST_TABLE (a, b) VALUES 'ABCD',@Sqlp_b)"
  CMD.Parameters.Clear()
  CMD.Parameters.Add(New SqlClient.SqlParameter("@Sqlp_b", SqlDbType.VarChar,5))
  CMD.Parameters("@Sqlp_b").Value = 'YUI(O'
  Try
    CMD.ExecuteNonQuery()
  Catch ex As Exception
    ERRORECODE = 3
    ERROREMSG = ex.ToString
  End Try
End Function

Function begintransaction()
  CMD.CommandText = "BEGIN TRANSACTION"
  Try
    CMD.ExecuteNonQuery()
  Catch ex As Exception
    ERRORECODE = 1
    ERROREMSG = ex.ToString
  End Try
End Function

Function rollbacktransaction()
  CMD.CommandText = "ROLLBACK TRANSACTION"
  Try
    CMD.ExecuteNonQuery()
  Catch ex As Exception
    ERRORECODE = 1
    ERROREMSG = ex.ToString
  End Try
End Function

Function committransaction()
  CMD.CommandText = "COMMIT TRANSACTION"
  Try
    CMD.ExecuteNonQuery()
  Catch ex As Exception
    ERRORECODE = 1
    ERROREMSG = ex.ToString
  End Try
End Function

End Class
burton999
ぬし
会議室デビュー日: 2003/10/06
投稿数: 898
お住まい・勤務地: 東京
投稿日時: 2006-02-17 13:38
トランザクション処理をSqlCommandでやっているのですね。。。
SqlClient.SqlConnectionクラスにBeginTransaction()メソッドがあり
このメソッドがSqlTransactionを返すので、それを使用したほうがよろしいかと。
ちなみにSqlTransactionクラスはSqlComandクラスのTransactionプロパティに設定します。

SqlTransaction クラス
http://www.microsoft.com/japan/msdn/library/ja/cpref/html/frlrfsystemdatasqlclientsqltransactionclasstopic.asp?frame=true
Taito
常連さん
会議室デビュー日: 2005/07/21
投稿数: 43
投稿日時: 2006-02-17 13:51
引用:

burton999さんの書き込み (2006-02-17 13:38) より:
トランザクション処理をSqlCommandでやっているのですね。。。



ほとんど我流なんで…;なんかおかしい方法みたいですね、恥ずかしい…。
SqlClient.SqlConnectionクラスのBeginTransaction()メソッド
調べてから試してみようと思います。

burton999さん、ありがとうございました。
Taito
常連さん
会議室デビュー日: 2005/07/21
投稿数: 43
投稿日時: 2006-02-17 14:54
SQLparameterとトランザクションでエラーなく
実行できるようになりました。
burton999さん、ありがとうございました。

Imports System.Data.SqlClient
Public Class F_buhintori
  Dim CN As New SqlClient.SqlConnection
  Dim CMD As New SqlClient.SqlCommand
  Dim TRANS As SqlTransaction
  Dim ERRORECODE As Integer
  Dim ERROREMSG As String

Private Sub btn_受注取込_Click
  CN.ConnectionString = "Server=" & DB_SERVER & ";Initial Catalog=" & DB_CATALOG & ";User ID=" & DB_USER & ";Password=" & DB_PASSWORD & ";"
  CN.Open()
  TRANS = CN.BeginTransaction()
  CMD.Connection = CN
  CMD.Transaction = TRANS
  
  make_item()

  If ERRORECODE = 0 Then
    Try
      TRANS.Commit()
    Catch ex As SqlException
      Try
        TRANS.Rollback()
        ERRORECODE = 1
        ERROREMSG = ex.ToString
      Catch ex2 As SqlException
        ERRORECODE = 1
        ERROREMSG = ex2.ToString
      End Try
    End Try
  Else
    Try
      TRANS.Rollback()
    Catch ex As SqlException
      ERRORECODE = 1
      ERROREMSG = ex.ToString
    End Try
  End If

  If ERRORECODE = 0 Then
    MsgBox("取込が終了しました")
  Else
    MsgBox(ERROREMSG)
  End If
End Sub

Function make_item()
  CMD.CommandText = ="INSERT INTO TEST_TABLE (a, b) VALUES 'ABCD',@Sqlp_b)"
  CMD.Parameters.Clear()
  CMD.Parameters.Add(New SqlClient.SqlParameter("@Sqlp_b", SqlDbType.VarChar,5))
  CMD.Parameters("@Sqlp_b").Value = 'YUI(O'
  Try
    CMD.ExecuteNonQuery()
  Catch ex As Exception
    ERRORECODE = 3
    ERROREMSG = ex.ToString
  End Try
End Function

End Class
Jitta
ぬし
会議室デビュー日: 2002/07/05
投稿数: 6267
お住まい・勤務地: 兵庫県・海手
投稿日時: 2006-02-17 22:20
ん〜。。。まぁ、「動けばいい」なら、いいんですけど、今日、こんなソースをメンテして泣いたので。

* SqlClient.SqlConnection など、IDispose インターフェイスを実装したものは、必ず Dispose(または Close)してください。
* その為、クラス変数として宣言するのではなく、メソッド内に宣言して、スコープを限定してください。
* 例外は、必要なければキャッチしないでください。キーパー以外はハンドで反則ですよ
* 実際には複数の処理があるんだろうけど、もし、1ステートしか実行させないなら、トランザクションを貼る必要はないですよ。
* Function は、必ず戻り型を宣言してください。
コード:
Private Function CreateConnection(ByRef ConnectionString As String) As SqlConnection
    Return New SqlConnection(ConnectionString)
End Function

Private Sub btn_受注取込_Click(...)
    Dim connection As SqlConnection = Nothing
    Dim command As SqlCommand = Nothing
    Dim transaction As SqlTransaction = Nothing
    Try
        connection = CreateConnection(String.Format( _
            "Server={0};...", New Object {DB_SERVER, ... })
        ...
        transaction.Commit()
        connection.Close()
        MessageBox.Show("取込が終了しました", "情報", ...)

    Catch ex As Exception
        transaction.RollBack()
        MessageBox.Show(ex.Message _
            , ex.GetType().ToString(), ...)

    Finally
        If Not connection Is Nothing Then
            connection.Dispose()
        End If
        ...
    End Try
End Sub

じゃんぬねっと
ぬし
会議室デビュー日: 2004/12/22
投稿数: 7811
お住まい・勤務地: 愛知県名古屋市
投稿日時: 2006-02-18 02:11
いつも書いていることを先に書かれた...

私の場合はそれプラス、使う直前に変数を宣言して
必ず、Try 〜 Finally パターンを使ってもっとスコープを限定します。
Command、Transaction も一応 IDispose インターフェイスを実装しているので、
どうしても、Dispose しておかないとしっくりこない。

たいてい、Jitta さんの言うように「メソッド内」のみに記述することが多く、
数コマンド連続で実行することも少ないので、ラッパークラスを組むこともあります。
主にインデントの節約と、新人らの工数短縮などがその要因だったりしますが。

_________________
C# と VB.NET の入門サイト
じゃんぬねっと日誌

スキルアップ/キャリアアップ(JOB@IT)