プロが教えるわが家の防犯対策術!

タイムアウト、プールサイズの制限値

VB2010で業務アプリケーションの集計ツールを作成しています。
仕組みは単純で、下記の様にDateTimePicker(カレンダー)から日付を選び
ボタンクリックでフォーム内のデータグリッド内に集計値が入っていく仕組みです。

'カレンダー日付選択
Sub Aggregate()
'日付の取得
DateTimePicker1.Format = DateTimePickerFormat.Custom
DateTimePicker1.CustomFormat = "yyyy-MM-dd

1つのフォームにデータグリッドが10個ほどあるので画面遷移までに5秒くらいかかってしまいます。
1度目の表示は問題ないのですが、日付を選択し直し2度、3度と実行すると
”タイムアウトに達しました。プールから接続を制限する前にタイムアウト期間が過ぎました。
プールされた接続がすべて使用中で、プールサイズの制限値に達した可能性があります。”
と表示されてしまいます。開放も行っているつもりで原因がわかりません。
原因がわかれば教えていただきたいです。処理をスピードアップできる方法があればそれもお願いします。
接続文字は以下の通りです。

Function CONNECT(ByVal SqlText As String) As String
Dim St As String
Dim Cn As New System.Data.SqlClient.SqlConnection
Dim SQL As New System.Data.SqlClient.SqlCommand
Dim ServerName As String = "AAAAAAAAA"
Dim UserID As String = "BBBBBBBBB"
Dim Password As String = "CCCCCCC"
Dim DatabaseName As String = "DB"
Dim Adapter As New System.Data.SqlClient.SqlDataAdapter
Dim Table As New DataTable

Adapter.SelectCommand = SQL
SQL.Connection = Cn
SQL.CommandTimeout = 120
St = "Server=" & ServerName & ";"
St &= "User ID=" & UserID & ";"
St &= "Password=" & Password & ";"
St &= "Initial Catalog=" & DatabaseName
Cn.ConnectionString = St
SQL.CommandText = SqlText
Cn.Open()
Return SQL.ExecuteScalar
SQL.Connection = Nothing
SQL.Transaction = Nothing
SQL.Dispose()
Cn = Nothing
Cn.Dispose()
Cn.Close()
End Function

データグリッドの転記は下記の様なコードをずらっと書いています。
DataGridView10(2, 3).Value = CONNECT("SELECT COUNT(*)" & _
" FROM dbo.IOTBL, dbo.APLTBL" & _
" WHERE APLTBL.APLID=IOTBL.APLID" & _
" And (APLTBL.APLTYPE='JA01')" & _
" And (APLTBL.DELETED<>'1')" )

A 回答 (3件)

Return以後のコードは実行されませんよ。


このコードだと,作成したSqlConnectionがGCされるまで開きっぱなしになります。
その結果,接続数が増えすぎてエラーになっているのだと思います。

SqlConnectionとSqlCommandを作る時に,Usingブロックを使ってみてください。
これにより,正しくDisposeが呼び出され,接続が閉じられるようになります。

e.g.)
Using cn = New SqlConnection()
Using cm = New SqlCommand()
' ....
End Using
End Using
これは,
Dim cn As SqlConnection = Nothing
Try
cn = New SqlConnection()
Dim cm As SqlCommand = Nothing
Try
cm = New SqlCommand
' ...
Finally
If cm IsNot Nothing Then DirectCast(cm, IDisposable).Dispose()
End Try
Finally
If cn IsNot Nothing Then DirectCast(cn, IDisposable).Dispsoe()
End Try
とほぼ等価で,Usingブロックを出たタイミングでDisposeを呼び出してくれます。
# VB2005からの機能です。

この回答への補足

ありがとうございます。
Using Cnは具体的にこのコードの場合どこに入れればよいのでしょうか?

補足日時:2011/04/20 13:05
    • good
    • 0

ANo.2です。



元のコードから無駄をそぎ落としつつUsingを使うなら,

Function CONNECT(ByVal SqlText As String) As String
Dim Builder = New SqlConnectionStringBuilder()
Builder.DataSource = "AAAAAAAAA"
Builder.UserID = "BBBBBBBBB"
Builder.Password = "CCCCCCC"
Builder.InitialCatalog = "DB"

Using Cn = New SqlConnection(Builder.ConnectionString)
Using SQL = New SqlCommand(SqlText, Cn)
Cn.Open()
Return TryCast(SQL.ExecuteScalar(), String)
End Using
End Using
End Function

という感じになると思います。

UsingブロックはVisual Basicにおけるリソース管理の基礎でもあるので,
ちゃんと調べておいた方がよいと思います。
    • good
    • 0

はじめまして通るすがるともうします。

わたしははっきりいってADOは使ったことはないのですが(環境もないし)、基本的にDBの使用法として(1)でopn (2)sql発行 (3)close(Disconect)の手順で行うとおもうのですが、上記ソースの部分で以下の疑問があります。
 
0.上のソース 
1. Cn.Open()           <-dbへの接続
2.Return SQL.ExecuteScalar  <-sql発行
3.SQL.Connection = Nothing
4.SQL.Transaction = Nothing
5.SQL.Dispose()
6.Cn = Nothing
7.Cn.Dispose()
8.Cn.Close()            <- ここでクローズ?? (dbのdisconect?)
だとすると、8行目のまえに5行目から6行目ででインスタンス解放初期化していては8行目で何をクローズすればいいのか判断できないと思います(多分ここでタイムアウト?)。なので8行目は2行目の直下に書くべきでは?
あと、このソースの部分は同じ接続内容で連続して呼ばれるわけですよね?
だとするとわざわざ初期化(5行目から7行目)する必要ってあるのでしょうか?たとえ使用しなくなってもせっかくメモリに常駐されたのなら次に接続を要求したときにすでにメモリに常駐したところを使用しにいくと思うので記述しないほうが早く動作すると思います。もし、確実にメモリを解放し解放したところを確実に使用できるようにしたければ8行目の後に、ガベージコレクションを起動しなければならないと思います。(System.GC.Collect)。<例をあげるのならたとえば、EXCELを一度目立ち上げると2回目に立ち上げたときは1回目より高速い起動されますね!>なので記述しているソースは少し矛盾しているかと思います。
    • good
    • 0

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