Tomcat アプリケーションで Oracle データソース レベルで返される行を制限する方法はありますか?
maxRows
Javaコードのデータソースに設定した場合にのみ利用できるようです。データmaxRows="2"
ソースへの配置は適用されません。
返される行を制限する他の方法はありますか? コードを変更せずに?
構成レベルで利用できるものではありません。とにかく実行したいことを実行することを再確認することをお勧めします。setMaxRowsのjavadocを参照してください。Oracleでは、クエリのすべての行をフェッチして、範囲外の行を削除します。Oracleでうまく機能させるには、rownumを実際に使用する必要がありますが、構成でもそれを行うことはできません。
*注意: 以下のコードは純粋な例として提供されています。テストされていません *したがって、自分自身やコンピュータに危害を加えたり、顔を殴ったりする可能性があります。
SQL クエリの変更を避けたいが、クリーンなコードを維持したい (つまり、コードを保守しやすい状態に保つ) 場合は、ラッパーを使用してソリューションを設計できます。つまり、既存のクラスをラップする小さなクラス セットを使用することで、実際の DataSource、Connection、および Statement で動作していると考えられるアプリケーションの残りの部分で、必要なものをシームレスに実現できます。
1 - アプリケーションがすでに使用しているものに応じて、StatementWrapper または PreparedStatementWrapper クラスを実装します。これらのクラスは、通常の Statement または PreparedStatement インスタンスのラッパーです。これらは、内側のステートメントをすべての作業を行うデリゲートとして使用するだけで実装されますが、これが QUERY ステートメント (Statement.executeQuery() メソッド) である場合を除きます。その正確な状況でのみ、ラッパーはクエリを次の 2 つの文字列で囲みます: "SELECT * FROM (" and ") WHERE ROWNUM < "+maxRowLimit. 基本的なコード ラッパー コードについては、以下の DataSourceWrapper がどのように見えるかを参照してください。
2 - もう 1 つのラッパーを作成します。 ConnectionWrapper は、createStatement() で StatementWrapper を返し、prepareStatement() で PreparedStatementWrapper を返す Connection をラップします。これらは、ConnectionWrapper の delegateConnection.createStatement()/prepareStatement() を構築引数として受け取る、以前にコーディングされたクラスです。
3 - DataSourceWrapper を使用して手順を繰り返します。簡単なコード例を次に示します。
public class DataSourceWrapper implements DataSource
{
private DataSource mDelegate;
public DataSourceWrapper( DataSource delegate )
{
if( delegate == null ) { throw new NullPointerException( "Delegate cannot be null" );
mDelegate = delegate;
}
public Connection getConnection(String username, String password)
{
return new ConnectionWrapper( mDelegate.getConnection( username, password ) );
}
public Connection getConnection()
{
... <same as getConnection(String, String)> ...
}
}
4 - 最後に、その DataSourceWrapper をアプリケーションの DataSource として使用します。JNDI (NamingContext) を使用している場合、この変更は簡単です。
これらすべてのコーディングは、特に、委譲メソッドを自動的に実装する Eclipse や IntelliJ などのスマート IDE を使用している場合は、迅速かつ非常に簡単です。
問題は、返される行数を制限する理由です。これを行う理由はたくさんあります。1 つ目は、データベースから返されるデータを制限することです。私の意見では、これはほとんどの場合意味がありません。特定のデータのみを取得したい場合は、別のステートメントを使用するか、フィルター条件などを追加します。たとえば、Oracle の rownum を使用する場合、行 x を y にすることをデータベースに伝えるだけなので、取得した行にどのデータが含まれ、どのデータが含まれていないか正確にはわかりません。
2 番目のアプローチは、JDBC ドライバーから取得する ResultSet にすべてのデータが含まれないように、メモリー使用量を制限してパフォーマンスを向上させることです。Statement.setFetchSize()を使用して、ResultSet が保持する行数を制限できます。. フェッチされた行数を超えて ResultSet 内でカーソルを移動すると、JDBC ドライバーは不足しているデータをデータベースからフェッチします。(Oracle の場合、データベースは、JDBC ドライバーによって直接アクセスされる ref カーソルにデータを格納します)。
1 つのテーブルのみを扱うことがわかっている場合は、where ステートメントで rownum を使用してビューを定義し、行数を制限します。このように、行数は DB で制御され、クライアント アプリケーションからのクエリの一部として指定する必要はありません。返される行数を変更する場合は、クエリを実行する前にビューを再定義してください。
より動的な方法は、プロシージャを開発して多数の行を渡し、プロシージャがクライアントに ref_cursor を返すようにすることです。これには、DB でのハード解析を回避し、パフォーマンスを向上させるという利点があります。
一度に Java アプリに吸い込まれる量を制限する方法については、このページをご覧ください。別の投稿が指摘しているように、DB は引き続きすべてのデータをプルします。これは、ネットワークの使用と Java 側のメモリを制御するためのものです。
わかりました、コードを変更する必要があります。
このシナリオでは、アドホック レポート ツールを制限して、エンド ユーザーがあまりにも多くのレコードを引き戻し、使用できないレポートを生成しないようにしています。
私たちはすでにオラクルのコストベースのリソース管理を使用しています。