質問: new DataSet() ) { lock( this ) adapter.Fill( ds ); foreach( Data.DataTable item in ds.Tables ) ret.Add( item ); } } } return ret.ToArray(); } ```
回答: MySQL の Connector/NET の MySqlDataAdapter.Fill メソッドの中では MySqlDataReader を使っているはずです。 そして、MySQL のドキュメントの MySqlDataReader の説明には以下の記述があります。(ちなみにこれは SqlDataReader でも同じです) MySqlDataReader Class "While the MySqlDataReader is in use, the associated MySqlConnection is busy serving the MySqlDataReader, and no other operations can be performed on the MySqlConnection other than closing it. This is the case until the Close() method of the MySqlDataReader is called." という訳で、上記の制限からの推測かつ未検証ですが、 > > 1 MySQL でひとつのコネクション内で同時に DB へのアクセスを行う方法があれば教えてください。 > > > 「同時」の意味にもよりますが、MySqlDataReader を Close しないのであれば方法はないということになるはずです。 > > 2 「発生している問題」に書いた問題が発生するのは、同じコネクション内で複数のアクセスを行えないから。 > > > そうではなくて、上に書いた "While the MySqlDataReader is in use, the associated MySqlConnection is busy serving the MySqlDataReader, and no other operations can be performed on the MySqlConnection" の通りだと思います。 質問者さんが質問に書いたエラーメッセージがそれを裏付けてます。 > > であるならばひとつのアプリケーション内で異なるコネクションを張ることが出来れば解決するように思えます。(根本的な問題の解決になるかは置いておきます) ひとつのアプリケーション内で、かつ C# で、複数のコネクションを張る方法があれば教えてください。 > > > そうですね。MySQL のドキュメントの説明ではそれで解決しそうな気がします・・・が、今どのようなコードを書いているのですか? 今でも各 MySqlDataAdapter に異なる MySqlConnection をコネクションプールから取得しているようなコードだとすると、すでにそのようにしているが解決できてないということになりますけど。 > > 3 それ以外に、同時にアクセスする方法があるようでしたら教えてください。 > > > 上に書いたように「同時」の意味にもよりますが、質問に「スレッドやタスクを利用して」と書いてあったということはマルチスレッドアプリで「同時」に処理して時間短縮することを期待しているのでしょうか? でも、マルチスレッドアプリは実際には同時ではなくて、OS が高速でスレッドを切り替えながら実行していくということで、結局は質問に書いてあった、 > > 直列に実行していると時間的にきついところがあります。 > > > の「直列」と同じ(むしろ、スレッドの切り替えの分オーバーヘッドが増えて逆に遅くなる)と思うのですが。 アプリ側で何とかする手段があるとしても、リモートの DB サバ―へ tcp 接続しているとすると、そこは「直列」とならざるを得ませんけど? **【追記】** 一つ思い出したことがあるので追記します。 Microsoft のドキュメントの「DbDataAdapter.Fill メソッド (DataSet)」の説明に以下の記述があります。 "指定したクエリが複数の結果を返す場合は、クエリを返す各列の結果セットが個別のテーブルに格納されます。2 番目以降の結果セットには、指定されたテーブル名に整数値を追加した名前が付けられます。たとえば、Table、Table1、Table2 のようになります。" これは MySQL の Connector/NET の MySqlDataAdapter.Fill (DataSet) メソッドでも同じようです。 検証してみましたが、以下のコードのように複数の SELECT クエリ(以下の例では 3 つ)をセットすれば、DataSet に 3 つの DataTable を自動的に生成してくれます。 ``` string connString = "接続文字列"; string queryString = "SELECT * FROM city; SELECT * FROM country; SELECT * FROM countrylanguage"; DataSet dataset = new DataSet(); using (MySqlConnection connection = new MySqlConnection(connString)) { MySqlDataAdapter adapter = new MySqlDataAdapter(); adapter.SelectCommand = new MySqlCommand(queryString, connection); adapter.Fill(dataset); } ``` city, country, countrylanguage は MySQL のサンプルデータベース world に含まれるものです。確認のため DataGridView に表示して見ましたが、以下の画像の通りちゃんと取得できているようです。 !イメージ説明 という訳で、質問の、 > > 3 それ以外に、同時にアクセスする方法があるようでしたら教えてください。 > > > については上の手段を検討してはいかがでしょう? **【追記2】** 以下の記事に書いてあるように SqlDataReader を使って、それを Close しなくても複数の SELECT クエリの結果セットを取得することもできます。サンプルコードの reader.NextResult(); に注目してください。 接続文字列でのデータベース名の指定 自分は SQL Server の場合しか確認してませんが、興味がありましたら質問者さんの方で MySqlDataReader でも同じことができるかどうか確認してみてください。 上の【追記】で書いた MySqlDataAdapter.Fill (DataSet) メソッドで複数のクエリから複数の DataTable を取得する場合もそれを使っているはずなので、MySQL でも SQL Server と同じことができるのではないかと思います。 【追記】の方法【追記2】の方法ともラウンドトリップが 1 回で済むので、複数のクエリを投げて複数のラウンドトリップとならざるを得ない質問者さんの原案よりは早そうです。 後は、ホントに DataSet / DataTable を作る必要があるかどうかで、【追記】の方法にするか【追記2】の方法にするか選んではいかがですか?