java cassandra datastax-java-driver

java - Reutilizando PreparedStatement al usar Datastax Cassandra Driver?



datastax-java-driver (4)

Actualmente estoy usando el controlador Datastax Cassandra para Cassandra 2 para ejecutar cql3. Esto funciona correctamente Empecé a usar 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); } }

A veces recibo una advertencia del conductor en mi registro:

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.

Esta advertencia tiene sentido, pero no estoy seguro de cómo debería volver a utilizar PreparedStatement .

¿Debo simplemente crear todos mis PreparedStatement en un método constructor / init y simplemente usarlos?

Pero, ¿funciona esto bien cuando varios subprocesos usan el mismo PreparedStatement al mismo tiempo (especialmente llamando a PreparedStatement.bind() para enlazar objetos)


Estamos usando cassandra en una aplicación web con Spring. En nuestro caso creamos los PreparedStatements cuando el bean que encapsula la operación en contra de cf (nuestro repositorio) es instalado.

Aquí tienes un fragmento del código que estamos usando:

@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; }

De esta forma, las declaraciones preparadas se reutilizan cada vez que ejecutamos el método findByProject.


La solución anterior funcionará en caso de que el espacio clave esté arreglado. En el caso de un escenario de múltiples inquilinos, esta solución no será suficiente. Simplemente lo hice de la siguiente manera, donde el espacio de claves se pasa como argumento.

Compruebe el espacio de claves de la declaración preparada, si es el mismo que el argumento pasado, entonces no prepare la declaración ya que está preparada en este caso.

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()); }


Puede inicializar el PreparedStatement una vez y almacenarlo en la memoria caché mientras se ejecuta la aplicación. Debería estar disponible para su uso mientras el grupo de Cassandra esté activo.

Usar la declaración de múltiples hilos está bien (siempre y cuando no lo modifiques a través de los métodos setXXX() ). Cuando llama a bind (), el código debajo solo lee PreparedStatement y luego crea una nueva instancia de BoundStatement () que el hilo llamante puede mutar libremente.

Aquí está el código fuente , si tiene curiosidad (búsqueda de bind() ).


03-Apr-2017 10:02:24,120 WARN [com.datastax.driver.core.Cluster] (cluster1-worker-2851) Re-preparing already prepared query is generally an anti-pattern and will likely affect performance. Consider preparing the statement only once. Query=''select * from xxxx where cjpid=? and cjpsnapshotid =?''

Cree un grupo de objetos PreparedStatement, uno para cada consulta CQL.

Luego, cuando el cliente solicite estas consultas, busque el objeto PS en caché respectivo y proporcione valores llamando a bind() .

como explica Daniel, bind() hace un new BoundStmt(param) que hace que este hilo sea seguro.