DOBON.NET DOBON.NETプログラミング掲示板過去ログ

SqlCommandのExecuteReaderについて

環境/言語:[VB.NET 2005 / SQL Server 2005 / Win XP Pro]
分類:[(未選択)]

2007/03/14(Wed) 13:24:41 編集(投稿者)
2007/03/14(Wed) 13:24:37 編集(投稿者)

じゅでです。
いつもこちらの掲示板にはお世話になっております。

今回も少々困った事がありまして、こちらに質問させていただきます。

環境は
開発言語:VB.NET 2005
使用DB :SQL Server 2005
使用OS :Windows XP SP2

現在以下のような事をしております


Dim sqlCmd as SqlCommand = new SqlCommada(CreateSql(),DbConnection)
Dim SqlDrd as SqlDataReader = sqlCmd.ExecuteReader
If Not SqlDrd.HasRows Then
SqlDrd.Close()
return
End If

sqlDrd.Read()
Dim strData as String = sqlDrd("strData")
sqlDrd.Close()

※多少ソースは省略化してあります。

ここで初回のsqlDrdの取得には成功するのですが、
上記のコードをメソッドとして、別の処理から繰り返し呼び出すと
以下のようなエラーが発生します。

ExecuteReader は、コマンドに割り当てられた接続が保留状態であるローカルのトランザクションにあるとき、トランザクション オブジェクトを持つコマンドが必要です。コマンドの Transaction プロパティがまだ初期化されていません。

Transactionは確かに使っているのですが、上記のメソッドを呼び出す際は
まだTransactionすら作成していない状態です。

また、このエラーなのですが、数回出ると正常に再度通るようになります。
また処理が終了した後に再度呼び出すと、エラーがまた発生するようになります。

原因としてどのような事があるのでしょうか。
もしお分かりの方がいらっしゃいましたら、教えていただけないでしょうか。

よろしくお願いいたします。

以上
>Transactionは確かに使っているのですが、上記のメソッドを呼び出す際は
>まだTransactionすら作成していない状態です。
とのご説明については、
エラーの内容から考えれば、
初回は確かにそうなのでしょうが、
複数回呼ばれる際に他の経由してきた処理でトランザクションが開始されたまま放置されているのでしょう。
(=コミットもロールバックも通過してきていない)
トランザクションを使用してプログラミングされているようなのでご存知かと思いますが
トランザクションが開始されている場合、
同一コネクションを使用してコマンドの実行等を行う場合は同じトランザクションに属するように
明示する必要があります。

で、エラーの後再度呼びに来るとうまく動くのは、
どこかの処理でエラー発生時にロールバックするよう記述しているためたまたま
トランザクション外になっているとかではないですか。
じゅでです。
ご返信ありがとうございます。

> で、エラーの後再度呼びに来るとうまく動くのは、
> どこかの処理でエラー発生時にロールバックするよう記述しているためたまたま
> トランザクション外になっているとかではないですか。

いちようトランザクションを使用する関数自体は別に切り離しており
こんな感じになっているので

Private Function Upsert() as Integer

If Not エラーチェック関数() Then
return -1
End If

If Not トランザクション使う関数() Then
return -1
End If

End Function

※ソースは簡略化してあります。
 トランザクション使う関数の中でしかトランザクションを使用せず
 内部ではTry〜Catchでコミットかロールバックが走るようにはしてあります。

上記のような別のメソッドとして用意しているので、
今のところかかれているような事はないです。

また、エラーが起こる回数も微妙で、速い間隔で同様の処理を流すと
エラーが5回6回とおこるのですが、時間をあけて同様の処理を行うと
1回2回しかおこらないので、何かほかに原因があるのではと現在
調査中であります。
■No19316に返信(じゅでさんの記事)
> Transactionは確かに使っているのですが、上記のメソッドを呼び出す際は
> まだTransactionすら作成していない状態です。

Transactionはそうでも同じインスタンスのConnectionを使いまわしているとか。
何より、

> Dim sqlCmd as SqlCommand = new SqlCommada(CreateSql(),DbConnection)

DbConnectionというのがすごく気になります。
ローカルで作っているなら気にはしませんが。

それと、SqlCommadaではコンパイルエラーになりますね。
そちらのソースではSqlCommandになっているでしょうけど、手で転記するのは間違いのもとですよ。
じゅでです。
ご返信ありがとうございます。

>
> Transactionはそうでも同じインスタンスのConnectionを使いまわしているとか。
> 何より、
>
>>Dim sqlCmd as SqlCommand = new SqlCommada(CreateSql(),DbConnection)
>
> DbConnectionというのがすごく気になります。
> ローカルで作っているなら気にはしませんが。

画面毎にコネクションを作成して、
画面内でConnectionは同じものを使いまわしています。
もしかしてこれはやめた方がいいですか?
すいません勉強不足で。

>
> それと、SqlCommadaではコンパイルエラーになりますね。
> そちらのソースではSqlCommandになっているでしょうけど、手で転記するのは間違いのもとですよ。

すいません。
まったく同じソースをコピーするのも問題がありますので
その場で手でうっておりました。
見苦しいものをお見せしてすいません。
これについてはちょっとというかかなり恥ずかしいです。
注意します。
じゅでです。
お世話になっております。

追記です。

> Transactionはそうでも同じインスタンスのConnectionを使いまわしているとか。

っとあったのでコネクションをメソッドで作成してそちらを作るように修正してみました。

using localDbConnection = new SqlConnection(DbConnectionString)

同じ処理

end using

これで今のところエラーが出なくなったのですが、何が起こっていたかがなぞで
仕方がありません。
何がいけなかったのでしょうか?

いろいろ調べてはみてますが、Poolingここらへんに問題があったのでしょうか?
ご存知の方がおられましたらご教授下さい。お願いいたします。
■No19329に返信(じゅでさんの記事)
> これで今のところエラーが出なくなったのですが、何が起こっていたかがなぞで
> 仕方がありません。
> 何がいけなかったのでしょうか?

Transactionを一度開始した後だとどうなっているか式ウォッチでみてみては?
同じ変数を使っても再度インスタンス化して別のインスタンスにすれば問題ないでしょうけど。

> いろいろ調べてはみてますが、Poolingここらへんに問題があったのでしょうか?
> ご存知の方がおられましたらご教授下さい。お願いいたします。

プーリングはこの場合関係ないですよ。
今あなたが変更した実装でこそプーリングが使われています。

まあ、このあたりはすぐ理解しようとせず勉強していってください。
じゅでです。
ご返信ありがとうございました。

> Transactionを一度開始した後だとどうなっているか式ウォッチでみてみては?
> 同じ変数を使っても再度インスタンス化して別のインスタンスにすれば問題ないでしょうけど。
>

それもそうですね。
ちょっと見てみます。
ありがとうございます。

>
> プーリングはこの場合関係ないですよ。
> 今あなたが変更した実装でこそプーリングが使われています。
>
> まあ、このあたりはすぐ理解しようとせず勉強していってください。

すいません勉強不足で。
ちょっと勉強しなおしてきます。
ありがとうございました。
解決済み!

DOBON.NET | プログラミング道 | プログラミング掲示板