プロが教える店舗&オフィスのセキュリティ対策術

 
お世話になります。

開発言語:VisualBasic 6 sp6
OS :WindowsXP Pro sp3
DB :Microsoft SQL Server 2005

以下のコードはCommand1ボタンをクリックした時に実行される処理です。

処理内容は、テーブルAを読み、テーブルAの全てのレコードを順次読みながら
テーブルBを検索し、テーブルBの"keyname"をprintします。
※実際のプログラムではテーブルAを順次読むループの中で多数のテーブルへの
 新規レコード追加、更新などを行っております。

Private Sub Command1_Click()
  Dim objConn   As ADODB.Connection
  Dim objRsA   As ADODB.Recordset
  Dim objRsB   As ADODB.Recordset
  Dim sSQL   As String

  Set objConn = New ADODB.Connection
  objConn.ConnectionString = cstrCon
  objConn.Open

  Set objRsA = New ADODB.Recordset
  Set objRsB = New ADODB.Recordset

  'トランザクション開始
  objConn.BeginTrans

  sSQL = "select * from テーブルA"
  objRsA.Open strSQL, objConn

  If objRsA.EOF = False Then
    Do Until objRsA.EOF
      sSQL = "select * from テーブルB where key = " & objRsA.Fields("key")

      objRsB.Open strSQL, objConn    '←この行でエラー発生

      Print objRsB.Fields("keyname").Value
      objRsB.Close
      objRsA.MoveNext
    Loop
  End If
  objRsA.Close
  'コミット
  objConn.CommitTrans
End Sub


↑の処理を実行すると「objRsB.Open strSQL, objConn」の行で以下の実行エラーになります。

"手動または分散トランザクションモードのため、新規接続を作成できません。"

このエラーの原因が分からず自分でもいろいろ調べてみました。
以下のサイトも何度も見直してみましたがよく理解できませんでした。
http://support.microsoft.com/kb/234218/ja

どこが間違っていて、どこを修正すればエラーが出なくなるのでしょうか?
よろしくお願い致します。
 

A 回答 (3件)

http://support.microsoft.com/kb/234218/ja
には、
>MTS のトランザクション内で、開いている ADO Connection オブジェクトを複数の操作に使用する
>場合は、次の手順を推奨します。
>開いているすべてのレコードセットは、ほかの操作を実行する前に、接続を解除するか閉じるかして、
>何も設定されていない状態にします。
>使われていないすべての Command オブジェクトは、何も設定されていない状態にします。
## 推奨って書いているけど、こうしないとエラーになってできないのに。。。

つまり、
objRsB.Open strSQL, objConn
をしようとしているときには、
objRsA.Open strSQL, objConn
の方は、closeして、set objRsA = nothing 等を使ってクリアを済ませていないとエラーとなる
ということです。
⇒今、書いているソースの方法はできないということ。

対策1
Set objConn = New ADODB.Connection

Set objConnA = New ADODB.Connection
Set objConnB = New ADODB.Connection
にして、
objRsA.Open strSQL, objConn

objRsA.Open strSQL, objConnA
および
objRsB.Open strSQL, objConn

objRsB.Open strSQL, objConnB
と変更する。(これで使いまわししていない状態となります)

対策2
sSQL = "select * from テーブルA"

sSQL = "select (使っている項目名を列記)from テーブルA,テーブルB"
& "where A.key = B.key"
として、
sSQL = "select * from テーブルB where key = " & objRsA.Fields("key")
objRsB.Open strSQL, objConn
を廃止。
・・・Selectの発行回数が、テーブルAのレコード件数+1回から、1回に減るのでこの方法のほうが
いいと思いますが。

あるいは、テーブルAのデータを全部配列に読み込んで、closeしてから、テーブルBの処理をする
等が考えられます。
    • good
    • 0
この回答へのお礼

 
返答ありがとうございます。
対策例まで書いて頂き助かります。

1つのコネクションで並行して2つ以上のレコードセットを使用できない
→わたしが質問で記述したソースはそのままでは実現できない

ということで理解しました。

ちなみに、対策1のようにコネクションを2つ使用する場合、
BeginTrans、CommitTrans、RollbackTransもそれぞれ2つずつ記述が必要ということですよね?

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

お礼日時:2012/06/21 09:16

ANo.2です。



すいません。
"手動または分散トランザクションモードのため、新規接続を作成できません。"
というエラーメッセージからみで、ちょっとごっちゃにしていました。

もし、MTSを使っておられるなら、トランザクション制御の命令は記述しません。
MTS側の設定で、トランザクション制御をサポートする指定にするだけです。
(IISやCOM+を使っているプログラムの場合。)

MTSを使っていない場合でしたら、
objConnA.BeginTrans
objConnB.BeginTrans
以下それぞれでトランザクション制御が必要です。
    • good
    • 0
この回答へのお礼

理解できました。
ありがとうございます。

お礼日時:2012/06/27 08:59

ANo1です。


お礼の、
>ちなみに、対策1のようにコネクションを2つ使用する場合、
>BeginTrans、CommitTrans、RollbackTransもそれぞれ2つずつ記述が必要ということですよね?
ですが、
MTSは分散トランザクションをサポートしているので1つで大丈夫です。

## 分散トランザクションって何?って聞かれそうですが。
## 簡単に言うと、複数のDBサーバ(複数の接続と言い換えてもいい)とのアクセスを
## 1つのトランザクションとしてまとめて処理できる機能とでも言えばいいかな。
    • good
    • 1
この回答へのお礼

お世話になっております。
※返信が遅れてしまい申し訳ありません。

> MTSは分散トランザクションをサポートしているので1つで大丈夫です。

1つで大丈夫という事ですが、具体的には BeginTrans、CommitTrans の記述はどの様に書けば良いのでしょうか?

1.objConnA.BeginTrans ?
2.objConnB.BeginTrans ?
3.まったく別の記述?

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

お礼日時:2012/06/25 10:23

お探しのQ&Aが見つからない時は、教えて!gooで質問しましょう!

このQ&Aを見た人はこんなQ&Aも見ています


このQ&Aを見た人がよく見るQ&A