From c1dfebb8228603b63781f389bcee4477079134a0 Mon Sep 17 00:00:00 2001 From: David Webb Date: Sat, 23 Nov 2013 01:02:55 -0500 Subject: [PATCH] Created BoundStatementFactory for high performance write ingestion. --- .../cassandra/core/BoundStatementFactory.java | 97 ++++++++++++++++++- .../cassandra/core/CassandraOperations.java | 2 + .../cassandra/core/CassandraTemplate.java | 16 +++ .../core/PreparedStatementCreatorFactory.java | 2 + .../template/CassandraOperationsTest.java | 14 +++ 5 files changed, 130 insertions(+), 1 deletion(-) diff --git a/src/main/java/org/springframework/cassandra/core/BoundStatementFactory.java b/src/main/java/org/springframework/cassandra/core/BoundStatementFactory.java index 21c4fd1cd..df861ea69 100644 --- a/src/main/java/org/springframework/cassandra/core/BoundStatementFactory.java +++ b/src/main/java/org/springframework/cassandra/core/BoundStatementFactory.java @@ -15,6 +15,16 @@ */ package org.springframework.cassandra.core; +import java.util.LinkedList; +import java.util.List; + +import org.springframework.util.CollectionUtils; + +import com.datastax.driver.core.BoundStatement; +import com.datastax.driver.core.PreparedStatement; +import com.datastax.driver.core.Session; +import com.datastax.driver.core.exceptions.DriverException; + /** * This is the primary class in core for binding many values to a Cassandra PreparedStatement. * @@ -26,6 +36,91 @@ package org.springframework.cassandra.core; * @author David Webb * */ -public class BoundStatementFactory { +public class BoundStatementFactory implements PreparedStatementCreator, CqlProvider { + private final String cql; + private PreparedStatement preparedStatement; + private List> values = new LinkedList>(); + + public BoundStatementFactory(String cql) { + this.cql = cql; + } + + public void addValues(List... values) { + this.values.add(CollectionUtils.arrayToList(values)); + } + + public void addValues(Object[]... values) { + for (int i = 0; values != null && i < values.length; i++) { + this.values.add(CollectionUtils.arrayToList(values[i])); + } + } + + public void replaceValues(List... values) { + this.values = CollectionUtils.arrayToList(values); + } + + public void replaceValues(Object[]... values) { + noValues(); + for (int i = 0; values != null && i < values.length; i++) { + this.values.add(CollectionUtils.arrayToList(values[i])); + } + + } + + public void noValues() { + this.values = new LinkedList>(); + } + + /* (non-Javadoc) + * @see org.springframework.cassandra.core.CqlProvider#getCql() + */ + @Override + public String getCql() { + return this.cql; + } + + /* (non-Javadoc) + * @see org.springframework.cassandra.core.PreparedStatementCreator#createPreparedStatement(com.datastax.driver.core.Session) + */ + @Override + public PreparedStatement createPreparedStatement(Session session) throws DriverException { + if (preparedStatement == null) { + preparedStatement = session.prepare(this.cql); + } + return preparedStatement; + } + + /** + * Bind all values with the single CQL (PreparedStatement) and return BoundStatements read for execution. + * + * @return + * @throws DriverException + */ + public List bindValues() throws DriverException { + + LinkedList boundStatements = new LinkedList(); + + for (List list : this.values) { + + // Test the type of the first value + Object v = list.get(0); + + Object[] vls; + if (v instanceof CqlParameterValue) { + LinkedList valuesList = new LinkedList(); + for (Object value : list) { + valuesList.add(((CqlParameterValue) value).getValue()); + } + vls = valuesList.toArray(); + } else { + vls = list.toArray(); + } + + boundStatements.add(preparedStatement.bind(vls)); + + } + + return boundStatements; + } } diff --git a/src/main/java/org/springframework/cassandra/core/CassandraOperations.java b/src/main/java/org/springframework/cassandra/core/CassandraOperations.java index 991c9ec95..c5e547fde 100644 --- a/src/main/java/org/springframework/cassandra/core/CassandraOperations.java +++ b/src/main/java/org/springframework/cassandra/core/CassandraOperations.java @@ -48,6 +48,8 @@ public interface CassandraOperations { */ void execute(final String cql) throws DataAccessException; + void execute(BoundStatementFactory bsf); + /** * Executes the supplied CQL Query Asynchronously and returns nothing. * diff --git a/src/main/java/org/springframework/cassandra/core/CassandraTemplate.java b/src/main/java/org/springframework/cassandra/core/CassandraTemplate.java index 0e599926d..7c474210a 100644 --- a/src/main/java/org/springframework/cassandra/core/CassandraTemplate.java +++ b/src/main/java/org/springframework/cassandra/core/CassandraTemplate.java @@ -559,4 +559,20 @@ public class CassandraTemplate extends CassandraAccessor implements CassandraOpe } }); } + + /* (non-Javadoc) + * @see org.springframework.cassandra.core.CassandraOperations#execute(org.springframework.cassandra.core.BoundStatementFactory) + */ + @Override + public void execute(BoundStatementFactory bsf) { + + bsf.createPreparedStatement(getSession()); + + List statements = bsf.bindValues(); + + for (BoundStatement bs : statements) { + getSession().execute(bs); + } + + } } \ No newline at end of file diff --git a/src/main/java/org/springframework/cassandra/core/PreparedStatementCreatorFactory.java b/src/main/java/org/springframework/cassandra/core/PreparedStatementCreatorFactory.java index 677a20d7e..cbf34c58d 100644 --- a/src/main/java/org/springframework/cassandra/core/PreparedStatementCreatorFactory.java +++ b/src/main/java/org/springframework/cassandra/core/PreparedStatementCreatorFactory.java @@ -33,6 +33,8 @@ import com.datastax.driver.core.exceptions.DriverException; /** * @author David Webb * + * @deprecated - Pattern from JDBC Template, but DW doesn't like it. Use {@link BoundStatementFactory} + * */ public class PreparedStatementCreatorFactory { diff --git a/src/test/java/org/springframework/data/cassandra/test/integration/template/CassandraOperationsTest.java b/src/test/java/org/springframework/data/cassandra/test/integration/template/CassandraOperationsTest.java index 3945a1942..db2b14583 100644 --- a/src/test/java/org/springframework/data/cassandra/test/integration/template/CassandraOperationsTest.java +++ b/src/test/java/org/springframework/data/cassandra/test/integration/template/CassandraOperationsTest.java @@ -43,6 +43,7 @@ import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.cache.annotation.Cacheable; import org.springframework.cache.interceptor.DefaultKeyGenerator; +import org.springframework.cassandra.core.BoundStatementFactory; import org.springframework.cassandra.core.CachedPreparedStatementCreator; import org.springframework.cassandra.core.CassandraOperations; import org.springframework.cassandra.core.CqlParameter; @@ -195,6 +196,19 @@ public class CassandraOperationsTest { } + @Test + public void boundStatementFactoryTest() { + + String cql = "insert into book (isbn, title, author, pages) values (?, ?, ?, ?)"; + + BoundStatementFactory bsf = new BoundStatementFactory(cql); + bsf.addValues(new Object[] { "1234", "Moby Dick", "Herman Manville", new Integer(456) }, new Object[] { "2345", + "War and Peace", "Russian Dude", new Integer(456) }, new Object[] { "3456", "Jane Ayre", "Charlotte", + new Integer(456) }); + + cassandraTemplate.execute(bsf); + } + // @Test public void cachedPreparedStatementTest() {