現在、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()
を呼び出す場合)にうまくいきますか?
PreparedStatementを一度初期化して、アプリの実行中にキャッシュすることができます。 Cassandraクラスターが稼働している限り、使用できるはずです。
複数のスレッドからステートメントを使用することは問題ありません(setXXX()
メソッドを介してステートメントを変更しない限り)。 bind()を呼び出すと、その下のコードはPreparedStatementのみを読み取り、BoundStatement()の新しいインスタンスを作成します。これにより、呼び出し元のスレッドは自由に変更できます。
ここにソースコードがあります 、興味があれば(bind()
を検索してください)。
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を実行するたびに、準備されたステートメントが再利用されます。
上記の解決策は、キースペースが固定されている場合に機能します。マルチテナントシナリオの場合、このソリューションでは不十分です。キースペースが引数として渡される、私は単に次の方法で行いました。
プリペアドステートメントからキースペースを確認します。渡された引数と同じである場合は、この場合はすでに準備されているため、ステートメントを準備しないでください。
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());
}