Getting Started with Apache Cassandra and Java (Part II)
Requirements
To follow this tutorial, you should already have a running instance of Cassandra (a small cluster would be good, but not necessary), the Datastax Java driver installed (refer to Part I), and have gone through the 10 minute walkthrough here: http://planetcassandra.org/create-a-keyspace-and-table/.
Try it out
For this demo, we’re going to be creating a simple console application, almost identical to the one in Part I, only this time we will be exploring connection policies, prepared statements, and query builder. Open a text editor and create a java file with a “GettingStartedTwo” class and a single main method.
public class GettingStartedTwo { public static void main(String[] args) { Cluster cluster; Session session; ResultSet results; Row rows;
Then we can connect to our cluster and create a session instance.
// Connect to the cluster and keyspace "demo" Cluster cluster = Cluster.builder() .addContactPoint("localhost") .build(); Session session = cluster.connect("demo");
But wait, now that we are running a cluster instead of a single instance, we’ll want to put some safeguards in place incase of a failover. We can do this using a RetryPolicy.The retry policy determines the default behavior to adopt when a request either times out or a node is unavailable. We’re using the DefaultRetryPolicy in this case, which will retry queries either:
- on a read timeout, when enough replicas have replied but the data wasn’t received.
- on a write timeout, if we timeout while writing the log used by batch statements.
cluster = Cluster .builder() .addContactPoint("192.168.0.30") .withRetryPolicy(DefaultRetryPolicy.INSTANCE) .build(); session = cluster.connect("demo");
A load balancing policy will determine which node it is to run a query. Since a client can read or write to any node, sometimes that can be inefficient. If a node receives a read or write owned on another node, it will coordinate that request for the client. We can use a load balancing policy to control that action. The TokenAwarePolicy ensures that the request will go to the node or replica responsible for the data indicated by the primary key. It is wrapped around DCAwareRoundRobinPolicy to make sure the requests stay in the local datacenter. This is a good choice for us as, although we only have our one local cluster at the moment, we are already thinking about the next step, expanding to multi-datacenter.
cluster = Cluster .builder() .addContactPoint("192.168.0.30") .withRetryPolicy(DefaultRetryPolicy.INSTANCE) .withLoadBalancingPolicy( new TokenAwarePolicy(new DCAwareRoundRobinPolicy())) .build(); session = cluster.connect("demo");
Now that you are connected to the “demo” keyspace, let’s insert a user into the “users” table. This is exactly what we were doing in Part I earlier, but we’re doing it a little differently this time. Using prepared a statement is more secure and the most performant way to get data into or out of our database. Prepared statements only need to be parsed once by the cluster, and then then values are bound to variables and then we execute the bound statement to read/write data from the cluster.
// Insert one record into the users table PreparedStatement statement = session.prepare( "INSERT INTO users" + "(lastname, age, city, email, firstname)" + "VALUES (?,?,?,?,?);"); BoundStatement boundStatement = new BoundStatement(statement); session.execute(boundStatement.bind("Jones", 35, "Austin", "bob@example.com", "Bob"));
Using the Java driver, we can easily pull the user back out. In Part I of Getting Started with Apache Cassandra with Java, we used a string representation of CQL. Now (and for the rest of the tutorial), we are going to do the same with Query Builder, which is more secure and saves us from potential CQL injection attacks.
// Use select to get the user we just entered Statement select = QueryBuilder.select().all().from("demo", "users") .where(eq("lastname", "Jones")); results = session.execute(select); for (Row row : results) { System.out.format("%s %d \n", row.getString("firstname"), row.getInt("age")); }
Since it’s Bob’s birthday, we are going to update his age.
// Update the same user with a new age Statement update = QueryBuilder.update("demo", "users") .with(QueryBuilder.set("age", 36)) .where((QueryBuilder.eq("lastname", "Jones"))); session.execute(update); // Select and show the change select = QueryBuilder.select().all().from("demo", "users") .where(eq("lastname", "Jones")); results = session.execute(select); for (Row row : results) { System.out.format("%s %d \n", row.getString("firstname"), row.getInt("age"));
Now let’s delete Bob from the table, and print out all the information left in the users table. You’ll notice that Bob’s information no longer comes back after being deleted (others might, if you have inserted users previously).
// Delete the user from the users table Statement delete = QueryBuilder.delete().from("users") .where(QueryBuilder.eq("lastname", "Jones")); results = session.execute(delete); // Show that the user is gone select = QueryBuilder.select().all().from("demo", "users"); results = session.execute(select); for (Row row : results) { System.out.format("%s %d %s %s %s\n", row.getString("lastname"), row.getInt("age"), row.getString("city"), row.getString("email"), row.getString("firstname")); }
Make sure that the connection closes once you are done.
// Clean up the connection by closing it cluster.close(); } }
CQL is very similar to SQL, in many cases the same syntax will work. This makes querying for data very straightforward if you have a background with relational databases.You have just managed to connect to a Cassandra cluster and perform queries against a live (local) database. Hopefully this demonstrates just how easy it is to use Cassandra using the Java driver. A Gist of the complete console application for this sample is available on GitHub.
Reference: | Getting Started with Apache Cassandra and Java (Part II) from our JCG partner Rebecca Mills at the Planet Cassandra blog. |