从Web应用程序使用Cassandra驱动程序的正确方法是什么

时间:2014-07-10 23:38:27

标签: java cassandra cassandra-2.0

我想用Java和Cassandra 2.x(在Jersey框架上)构建一个RESTful API。我对这两种技术都很陌生,所以我想问你是集成和共享Cassandra驱动程序的正确方法。

0。通过Maven获取驱动程序

<dependency>
            <groupId>com.datastax.cassandra</groupId>
            <artifactId>cassandra-driver-core</artifactId>
            <version>2.0.3</version>
</dependency>

1。使用客户端类包装驱动程序的功能:

package com.example.cassandra;

import com.datastax.driver.core.*;

public class Client {

    private Cluster cluster;
    private Session session;

    public Client(String node) {
        connect( node );
    }

    private void connect(String node) {
        cluster = Cluster.builder()
            .addContactPoint(node)
            .build();

        session = cluster.connect();
    }

    public ResultSet execute( String cql3 ) {
        return session.execute( cql3 );
    }

    public void close() {
      cluster.close();
    }

}

2。我在ContextListener中对客户端进行了启动,并通过上下文属性

进行共享
package com.example.listener;

import javax.servlet.ServletContext;
import javax.servlet.ServletContextEvent;
import javax.servlet.ServletContextListener;

import com.example.cassandra.Client;

public class ExampleContextListener implements ServletContextListener {

    Client cassandraClient;

    public void contextInitialized(ServletContextEvent servletContextEvent) {
        ServletContext ctx = servletContextEvent.getServletContext();

        cassandraClient = new Client( ctx.getInitParameter( "DBHost" ) );
        ctx.setAttribute( "DB", cassandraClient );
    }

    public void contextDestroyed(ServletContextEvent servletContextEvent) {
        cassandraClient.close();
    }

}

第3。现在我从servlet的上下文中获取客户端并使用它

Client client =  (Client) context.getAttribute("DB");
client.execute("USE testspace;");

ResultSet rs = client.execute("SELECT * from users;");
for (Row row : rs ) {
    output += row.getString("lname") + "|";
}

这是正确的方法吗(从性能和架构的角度来看)?

完整示例:https://github.com/lukaszkujawa/jersey-cassandra

1 个答案:

答案 0 :(得分:10)

我刚刚开发了你要开发的东西。你写的是有效的,但这不是我最喜欢的方法。我宁愿创建一个Singleton(因为1个会话足够用于应用程序)。以下是Joshua Bloch enum的单身人士模式,这就是我做的事情

    public enum Cassandra {

        DB;

        private Session session;
        private Cluster cluster;
        private static final Logger LOGGER = LoggerFactory.getLogger(Cassandra.class);

        /**
         * Connect to the cassandra database based on the connection configuration provided.
         * Multiple call to this method will have no effects if a connection is already established
         * @param conf the configuration for the connection
         */
        public void connect(ConnectionCfg conf) {
            if (cluster == null && session == null) {
                cluster = Cluster.builder().withPort(conf.getPort()).withCredentials(conf.getUsername(), conf.getPassword()).addContactPoints(conf.getSeeds()).build();
                session = cluster.connect(conf.getKeyspace());
            }
            Metadata metadata = cluster.getMetadata();
            LOGGER.info("Connected to cluster: " + metadata.getClusterName() + " with partitioner: " + metadata.getPartitioner());
            metadata.getAllHosts().stream().forEach((host) -> {
                LOGGER.info("Cassandra datacenter: " + host.getDatacenter() + " | address: " + host.getAddress() + " | rack: " + host.getRack());
            });
        }

        /**
         * Invalidate and close the session and connection to the cassandra database
         */
        public void shutdown() {
            LOGGER.info("Shutting down the whole cassandra cluster");
            if (null != session) {
                session.close();
            }
            if (null != cluster) {
                cluster.close();
            }
        }

        public Session getSession() {
            if (session == null) {
                throw new IllegalStateException("No connection initialized");
            }
            return session;
        }
}

在上下文监听器中,我调用connect或shutdown。 由于新驱动程序中的所有异常都未被检查,因此我的建议是创建自己的Jersey ExceptionMapper映射DriverException实现。还有一件事,考虑使用PreparedStatements而不是字符串,以便Cassandra只解析一次查询。在我的应用程序中,我也按照上面的模式进行查询(第一次加载时准备语句的枚举单例,然后公开使用这些语句的方法)。

HTH, 卡罗