I need to query one of the tables in Cassandra using Datastax Java driver. Below is the code I have which works fine -
public class TestCassandra {
private Session session = null;
private Cluster cluster = null;
private static class ConnectionHolder {
static final TestCassandra connection = new TestCassandra();
}
public static TestCassandra getInstance() {
return ConnectionHolder.connection;
}
private TestCassandra() {
Builder builder = Cluster.builder();
builder.addContactPoints("127.0.0.1");
PoolingOptions opts = new PoolingOptions();
opts.setCoreConnectionsPerHost(HostDistance.LOCAL, opts.getCoreConnectionsPerHost(HostDistance.LOCAL));
cluster = builder.withRetryPolicy(DowngradingConsistencyRetryPolicy.INSTANCE).withPoolingOptions(opts)
.withLoadBalancingPolicy(new TokenAwarePolicy(new DCAwareRoundRobinPolicy("DC2")))
.withReconnectionPolicy(new ConstantReconnectionPolicy(100L))
.build();
session = cluster.connect();
}
private Set<String> getRandomUsers() {
Set<String> userList = new HashSet<String>();
for (int table = 0; table < 14; table++) {
String sql = "select * from testkeyspace.test_table_" + table + ";";
try {
SimpleStatement query = new SimpleStatement(sql);
query.setConsistencyLevel(ConsistencyLevel.QUORUM);
ResultSet res = session.execute(query);
Iterator<Row> rows = res.iterator();
while (rows.hasNext()) {
Row r = rows.next();
String user_id = r.getString("user_id");
userList.add(user_id);
}
} catch (Exception e) {
System.out.println("error= " + ExceptionUtils.getStackTrace(e));
}
}
return userList;
}
}
I am using above class like this in my main application -
TestCassandra.getInstance().getRandomUsers();
Is there any way I can use PreparedStatement
in getRandomUsers
efficiently? I guess I need to make sure that I am creating PreparedStatement
only once instead of creating it multiple times. What is the best design for that in my current architecture and how can I use it?
Preparing statements A prepared statement is a cassandra query that has been pre-parsed and validated by the cassandra database. Ideally you prepare a query once, and then use it many times by binding values to binding variables in the query.
Prepared statements are much faster when you have to run the same statement multiple times, with different data. Thats because SQL will validate the query only once, whereas if you just use a statement it will validate the query each time.
A prepared statement with values bound to the bind variables. Once values has been provided for the variables of the PreparedStatement it has been created from, such BoundStatement can be executed (through Session. execute(Statement) ). The values of a BoundStatement can be set by either index or name.
You can create a cache (this is a fairly basic example to give you an idea) of the statements you need. Lets start by creating the class that will be used as a cache.
private class StatementCache {
Map<String, PreparedStatement> statementCache = new HashMap<>();
public BoundStatement getStatement(String cql) {
PreparedStatement ps = statementCache.get(cql);
// no statement cached, create one and cache it now.
if (ps == null) {
ps = session.prepare(cql);
statementCache.put(cql, ps);
}
return ps.bind();
}
}
Then add an instance to your singleton:
public class TestCassandra {
private Session session = null;
private Cluster cluster = null;
private StatementCache psCache = new StatementCache();
// rest of class...
And finally use the cache from your function:
private Set<String> getRandomUsers(String cql) {
// lots of code.
try {
SimpleStatement query = new SimpleStatement(cql);
query.setConsistencyLevel(ConsistencyLevel.QUORUM);
// abstract the handling of the cache to it's own class.
// this will need some work to make sure it's thread safe
// as currently it's not.
ResultSet res = session.execute(psCache.getStatement(cql));
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With