web-dev-qa-db-ja.com

JDBCTemplateで準備されたステートメントを使用する

JDBCテンプレートを使用しており、準備済みステートメントを使用してデータベースから読み取りたい。 .csvファイルの多くの行を反復処理し、各行で、対応する値を使用していくつかのSQL選択クエリを実行します。

データベースからの読み取りを高速化したいのですが、JDBCテンプレートを準備済みステートメントで動作させる方法がわかりません。

PreparedStatementCreatorPreparedStatementSetter があります。 この例 のように、両方とも匿名の内部クラスで作成されます。しかし、PreparedStatementSetterクラス内では、preparedステートメントで設定したい値にアクセスできません。

.csvファイルを繰り返し処理しているので、それらを文字列としてハードコーディングすることはできません。また、コンストラクターの引数がないため、それらをPreparedStatementSetterに渡すこともできません。そして、私の値をfinalに設定するのも愚かなことです。

かなり単純な準備済みステートメントの作成に慣れていました。何かのようなもの

PreparedStatement updateSales = con.prepareStatement(
    "UPDATE COFFEES SET SALES = ? WHERE COF_NAME LIKE ? ");
updateSales.setInt(1, 75); 
updateSales.setString(2, "Colombian"); 
updateSales.executeUpdate():

このように Javaチュートリアル

26
user321068

PreparedStatement を使用してselectステートメントを試しましたが、Jdbcテンプレートよりも高速ではないことがわかりました。 mezmoが示唆したように、準備されたステートメントを自動的に作成するかもしれません。

とにかく、私のsql SELECTsが非常に遅いのは別の理由です。 WHERE句では、正確に一致するものを見つけたいだけであるときに、常に演算子LIKEを使用しました。 LIKEがパターンを検索することがわかったので、かなり遅いです。

演算子=を使用していますが、はるかに高速です。

2
user321068

.update(String sql, Object ... args)形式を使用する場合、デフォルトでは、JDBCTemplateは内部で独自のPreparedStatementを実行します。 Springとデータベースはコンパイルされたクエリを管理するため、開く、閉じる、リソース保護などについて心配する必要はありません。Springの保存猶予の1つです。 これに関するSpring 2.5のドキュメントへのリンク。 物事がより明確になることを願っています。また、 少なくともOracleのJDBCドライバーの一部 の場合のように、ステートメントのキャッシュはJDBCレベルで実行できます。

28
mezmo
class Main {
    public static void main(String args[]) throws Exception {
        ApplicationContext ac = new
          ClassPathXmlApplicationContext("context.xml", Main.class);
        DataSource dataSource = (DataSource) ac.getBean("dataSource");
// DataSource mysqlDataSource = (DataSource) ac.getBean("mysqlDataSource");

        JdbcTemplate jdbcTemplate = new JdbcTemplate(dataSource);

        String prasobhName = 
        jdbcTemplate.query(
           "select first_name from customer where last_name like ?",
            new PreparedStatementSetter() {
              public void setValues(PreparedStatement preparedStatement) throws
                SQLException {
                  preparedStatement.setString(1, "nair%");
              }
            }, 
            new ResultSetExtractor<Long>() {
              public Long extractData(ResultSet resultSet) throws SQLException,
                DataAccessException {
                  if (resultSet.next()) {
                      return resultSet.getLong(1);
                  }
                  return null;
              }
            }
        );
        System.out.println(machaceksName);
    }
}
19
Prasobh.K

以下を試してください:

PreparedStatementCreator creator = new PreparedStatementCreator() {
    @Override
    public PreparedStatement createPreparedStatement(Connection con) throws SQLException {
        PreparedStatement updateSales = con.prepareStatement(
        "UPDATE COFFEES SET SALES = ? WHERE COF_NAME LIKE ? ");
        updateSales.setInt(1, 75); 
        updateSales.setString(2, "Colombian"); 
        return updateSales;
    }
};
10
Kevin

準備済みのステートメント処理を少なくとも1つのメソッドに分解します。この場合、結果がないため、かなり単純です(そして、接続が変更されないインスタンス変数であると仮定します):

private PreparedStatement updateSales;
public void updateSales(int sales, String cof_name) throws SQLException {
    if (updateSales == null) {
        updateSales = con.prepareStatement(
            "UPDATE COFFEES SET SALES = ? WHERE COF_NAME LIKE ?");
    }
    updateSales.setInt(1, sales);
    updateSales.setString(2, cof_name);
    updateSales.executeUpdate();
}

その時点で、それは呼び出すだけの問題です:

updateSales(75, "Colombian");

他のものと統合するのはどちらが非常に簡単ですか?そして、メソッドを何度も呼び出すと、更新は一度だけ構築され、それにより物事がずっと速くなります。さて、あなたはそれ自体のトランザクションで各更新を行うような狂ったことをしないと仮定します...

タイプは固定されていることに注意してください。これは、特定のクエリ/更新では、データベースが効率的にジョブを実行できるように、shouldを修正するためです。 CSVファイルから任意の文字列を取得するだけの場合は、文字列として渡します。ロックもありません。代わりに、単一のスレッドから使​​用される個々の接続を維持する方がはるかに優れています。

3
Donal Fellows