PreparedStatement を close しないとカーソルが close されない? : まずは PreparedStatement とカーソルをおさらい

Oracle DB に DBUtils を使う Java プログラムから接続していて、とある処理をさせていたら「ORA-01000 最大オープン・カーソル数を超えました」というエラーが出た。

よくよくプログラムを見ると、SELECT の時だけ DBUtils を使わず生の PreparedStatement を使って SELECT しており、その SELECT 処理が for ループの中で何度も呼び出されている間にエラーが発生していた (どういうプログラムなんだ、というツッコミはおいといて…全体的にクソコードなんです…)。

んー、でも、PreparedStatement を使っているとカーソルも使うのか?

イマイチ DB のこととか分かってなかったので勉強し直した。独自解釈で、今回の問題を解決するための範囲でしか調べてないので多分に誤解があるかも。

PreparedStatement とは

Prepared、準備。Statement、構文。とでも訳すといいかな。事前にコンパイルしておいた問合せ文を保持したり、問合せ結果を使うためのオブジェクト。

Statement と違って PreparedStatement はシングルクォートなどの文字列をエスケープしてくれるので、SQL インジェクション対策になる、程度の知識しかなかった。

SQL 実行時にカーソルというオブジェクトが作られる

この知識がなかった。

普通の SQL で SELECT 文や UPDATE 文などを投げる時に、その検索条件だったり、探索位置だったりを保持するためのオブジェクトが自動的に DB にできているらしい。これが「カーソル」ってモノらしい。

カーソルというと、PL/SQL でプログラムを作る時に SELECT 結果を回すためのモノ、と思ってたので、普通の SELECT 文にも関わってくると思ってなかった。よくよく考えたら PL/SQL におけるカーソルは、通常の SELECT 文を DB が自動的に実行してあれこれやってくれているところに横入りして、人間がカーソルを操作してるってことなんだね。

PreparedStatement とカーソルがどう関係するのか?

Java プログラムから PreparedStatement を使って SELECT する場合も、結局は DB に SQL 文を発行しているわけだから、DB の内部にはカーソルオブジェクトが生成される。だから、ダメなコードだとカーソルが開きっぱなしになってエラーが発生するようだ。

実際にどうしてエラーが発生してしまうのか、どうしたら直せるのか、については次回。