dポイントプレゼントキャンペーン実施中!

MySQL5.5.27, mysql-connector-java-5.1.12を用いて、DBにアクセスしています。

DBに登録されたテーブル名を取得しようと思い、以下の様なメソッドを作成しました(テーブル名は全て数字です)。
https://gist.github.com/4146754

しばらくは順調に動いていたのですが、DBに登録されたレコード数が25万を超えたあたりで、動かなくなってしまいました。
デバッグをして原因を調べたところ、
metadata.getTables(null, "%", "%", null);
の実行時に、メソッドを呼び出したまま固まってしまっていることが分かりました。

同じコードを、別のDBに対して作用させたところ、問題なく動いたため、レコード数が多いのが原因ではないのかと考えたのですが、何かよい対処法はありますでしょうか?

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

A 回答 (3件)

> getTablesに関しては、jdbcのDatabaseMetadataに元からあるメソッドで、javadocは↓の通りです。


これは失礼しました(汗)
デバッグできてなくてOKです…

> コネクションに関しましては、一度つないだあと、使いまわす形になっています(使い回しはやはりまずかったのでしょうか…?)
Class.forName("com.mysql.jdbc.Driver");
で使いまわしはあまり良くないです。

今Gistに上げられているソースは問題なさそうですねぇ。

では、問題を切り分けていきましょう!
まずはMySQLに「SHOW TABLES;」で
一覧が問題なく取得できるか確認します。
これで問題なく取得できればMySQL側は問題なしです。

次に、ソースを生のSQLではどうか試してみます。
以下のようなソースに書き換えてみてください。
(インデントがなくてすいません…)

public ArrayList<Long> getExistsTable() {
ArrayList<Long> existsTable = new ArrayList<Long>();
ResultSet rs = null;
Connection connection = null;
PreparedStatement ps = null;

try {
// ドライバクラスをロード
Class.forName("com.mysql.jdbc.Driver");
// データベースへ接続
connection = DriverManager.getConnection("jdbc:mysql://localhost/" + "databaseName","userName","password");
} catch (ClassNotFoundException e) {
e.printStackTrace();
} catch (SQLException e) {
e.printStackTrace();
}

try {
ps = connection.prepareStatement("SHOW TABLES");
rs = ps.executeQuery();
while(rs.next()){
try{
existsTable.add(rs.getLong(1));
}catch(NumberFormatException e){
// e.printStackTrace();
}
}
} catch (SQLException e) {
e.printStackTrace();
} finally {
try {
if(rs != null){
rs.close();
}
if(ps != null){
ps.close();
}
if(connection != null){
connection.close();
}
} catch (SQLException e) {
e.printStackTrace();
}
}
System.out.println("size = " + existsTable.size());
return existsTable;
}
(本当はこんなチマチマ閉じなくていいのですが)

これで問題なければ
DatabaseMetaData metadata = connection.getMetaData();
がよくなかったということになります。
(たまにJavaでもバグはあるものです。)

あとは25万件との話ですが、HDDの容量は大丈夫ですか?

この回答への補足

ソースコードまでご提示いただきありがとうございます!


>> コネクションに関しましては、一度つないだあと、使いまわす形になっています(使い回しはやはりまずかったのでしょうか…?)
> Class.forName("com.mysql.jdbc.Driver");
> で使いまわしはあまり良くないです。

本筋から外れてしまってすみませんが、「Class.forName("com.mysql.jdbc.Driver");で使い回し」とはどういった意味でしょうか…?
また、コネクションはSQL文を一回発行するごとに確立し、実行が終わるたびに閉じるのがやはり理想的なのでしょうか?


> まずはMySQLに「SHOW TABLES;」で
> 一覧が問題なく取得できるか確認します。

時間はかかりましたが、問題なく取得できました!


ご提示頂いたソースコードも上手く動きました!
PreparedStatementを使うと「SHOW ...」のような文も実行できるんですね。勉強になりました。


HDDの容量は、まだ300GB以上余っているため、特に問題はないと思います。


となると、元のソースコードが動かなかったのはやはりjdbcの方のバグなんでしょうかね…

補足日時:2012/11/27 16:28
    • good
    • 0

> 本筋から外れてしまってすみませんが、「Class.forName("com.mysql.jdbc.Driver");で使い回し」とはどういった意味でしょうか…?


そう言われると…どういう意味でしょうね(^^;
いや、使いまわしはよくないですよ…と言いたかったのです(汗)

> また、コネクションはSQL文を一回発行するごとに確立し、実行が終わるたびに閉じるのがやはり理想的なのでしょうか?
はい、理想的です。
ムダなメモリーも食いませんし、不必要なバグに怯える必要もなくなります。
また、コネクションの確立も今のPCであれば大した速度でもないでしょうし。

ただ、使いまわしも1処理内であればいいと思います。
例えばfor文で回してる間にいちいち閉じるのは非現実的なので、
for文が始まる前に確立させて使いまわす…は、アリかもしれません。
この辺りは人の感覚やソースにもよりますので、一概には言えません。
不安があるウチは、実行が終わるたびに閉じるようにした方がよいでしょう。

この辺の事情は難しいですよね。
自分で言ってても正しいのか不安です…。
なので、DataSourceを使用しないのであればかなり気を付けるようにしています。

> となると、元のソースコードが動かなかったのはやはりjdbcの方のバグなんでしょうかね…
全ソースを見てないので何ともですが、そうなのかもしれませんね。
今お使いのJDKは5以上とお見受けしますが、元のソースコードは
1.4.2なので、この辺りも関係しているかもしれません。

何はともあれ、動いて良かったですね!
    • good
    • 0
この回答へのお礼

>> 本筋から外れてしまってすみませんが、「Class.forName("com.mysql.jdbc.Driver");で使い回し」とはどういった意味でしょうか…?
> そう言われると…どういう意味でしょうね(^^;
> いや、使いまわしはよくないですよ…と言いたかったのです(汗)

揚げ足をとってしまったようですみません(汗)
何か他のコネクション確立方法があるのかと思ってしまいました


コネクションの確立タイミングにつきましても、細かく答えていただきましてありがとうございました。
今後の参考にさせていただきます。


Javaのバージョンは1.6.0_27なので、確かに参照していたjavadocのバージョンと異なっていましたね…
バージョン違いも細かくチェックする癖をつけていこうと思います。


細かい質問にも丁寧に答えていただき、本当にありがとうございました!

お礼日時:2012/11/27 19:55

こんにちは!



getTablesの内容がないので何ともですが(^^;
getTablesメソッドの中まではデバッグしてないですか?

私の経験ではこういう場合、コネクションを閉じていなかったとか
辺に再利用したとか、Java側の凡ミスが多いです。

ResultSetやConnectionはドコで閉じてますか?
Githubのソースを端折らずに提示してもらえると
回答もしやすいかな~って感じです。

この回答への補足

ご回答頂きありがとうございます。
また、質問内容に不備がありすみませんでした。

getTablesに関しては、jdbcのDatabaseMetadataに元からあるメソッドで、javadocは↓の通りです。
中まではデバッグしきれていないです…
http://docs.oracle.com/javase/1.4.2/docs/api/jav … java.lang.String, java.lang.String, java.lang.String[])

コネクションに関しましては、一度つないだあと、使いまわす形になっています(使い回しはやはりまずかったのでしょうか…?)
ResultSetも閉じ忘れていますね…

とりあえず、頂いたアドバイスを元に、下記の通り修正しました(テーブル名、ユーザ名、パスワードは伏せさせて頂きました)。
ですが、まだ同様の現象が起きてしまいます。
https://gist.github.com/4146754

更に思い当たる解決法がありましたら、教えて頂ければと思います。
よろしくお願い致します。

補足日時:2012/11/27 11:30
    • good
    • 0

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