web-dev-qa-db-ja.com

Datastaxを使用するときにPreparedStatementを再利用するCassandra Driver?

現在、Datastax Cassandraドライバーfor Cassandra 2を使用してcql3を実行しています。これは正しく機能します。_PreparedStatement's_を使用し始めました:

_Session session = sessionProvider.getSession();
try {
    PreparedStatement ps = session.prepare(cql);
    ResultSet rs = session.execute(ps.bind(objects));
    if (irsr != null) {
       irsr.read(rs);
    }
}
_

ログにドライバーから警告が表示されることがあります。

_Re-preparing already prepared query . Please note that preparing the same query more than once is generally an anti-pattern and will likely affect performance. Consider preparing the statement only once.
_

この警告は理にかなっていますが、PreparedStatementを再利用する方法がわかりませんか?

コンストラクター/ initメソッドですべてのPreparedStatementを作成し、単にそれらを使用する必要がありますか?

しかし、これは、複数のスレッドが同時に同じPreparedStatementを使用する場合(特にオブジェクトをバインドするためにPreparedStatement.bind()を呼び出す場合)にうまくいきますか?

14
TinusSky

PreparedStatementを一度初期化して、アプリの実行中にキャッシュすることができます。 Cassandraクラスターが稼働している限り、使用できるはずです。

複数のスレッドからステートメントを使用することは問題ありません(setXXX()メソッドを介してステートメントを変更しない限り)。 bind()を呼び出すと、その下のコードはPreparedStatementのみを読み取り、BoundStatement()の新しいインスタンスを作成します。これにより、呼び出し元のスレッドは自由に変更できます。

ここにソースコードがあります 、興味があれば(bind()を検索してください)。

20
Daniel S.

Springを使用するWebアプリケーションでcassandraを使用しています。この場合、cf(リポジトリ)に対する操作をカプセル化するBeanがインスタンス化されるときにPreparedStatementsを作成します。

ここに、使用しているコードのスニペットがあります。

@Repository
public class StatsRepositoryImpl implements StatsRepository {

@SuppressWarnings("unused")
    @PostConstruct
    private void initStatements(){
        if (cassandraSession == null){
            LOG.error("Cassandra 2.0 not available");
        } else {
            GETSTATS_BY_PROJECT = cassandraSession.prepare(SELECTSTATS+" WHERE projectid = ?");
        }

    }       

@Override
    public Stats findByProject(Project project) {
        Stats stats = null;

        BoundStatement boundStatement = new BoundStatement(GETSTATS_BY_PROJECT);

        ResultSet rs = cassandraSession.execute(boundStatement.bind(project.getId()));
        for (Row row : rs){
            stats = mapRowToStats(row);
        }

        return stats;
    } 

このようにして、メソッドfindByProjectを実行するたびに、準備されたステートメントが再利用されます。

9
ftrujillo

上記の解決策は、キースペースが固定されている場合に機能します。マルチテナントシナリオの場合、このソリューションでは不十分です。キースペースが引数として渡される、私は単に次の方法で行いました。

プリペアドステートメントからキースペースを確認します。渡された引数と同じである場合は、この場合はすでに準備されているため、ステートメントを準備しないでください。

 private BatchStatement eventBatch(List<SomeEvent> events, String keySpace) {

    BatchStatement batch = new BatchStatement();
    String preparedStmtKeySpace = propEventPer == null? "" : propEventPer.getQueryKeyspace();
    if(!keySpace.equals("\"" + preparedStmtKeySpace +  "\"")) {
        eventStmt = cassandraOperations.getSession().prepare(colFamilyInsert(keySpace + "." + "table_name"));

    }
    ....
private RegularStatement colFamilyInsert(String colFamilyName) {
    return insertInto(colFamilyName)
            .value(PERSON_ID, bindMarker())
            .value(DAY, bindMarker());

}
0
Harvinder Singh