Java Cassandra-使用带ListenableFuture的PreparedStatement
我正在尝试使用ListenableFuture对Cassandra群集进行异步写入,如下所示:Java Cassandra-使用带ListenableFuture的PreparedStatement,java,cassandra,Java,Cassandra,我正在尝试使用ListenableFuture对Cassandra群集进行异步写入,如下所示: private static Cluster cluster = null; private ListeningExecutorService executorService; private PreparedStatement preparedStatement; private Session session = null; ... executorService = MoreExecuto
private static Cluster cluster = null;
private ListeningExecutorService executorService;
private PreparedStatement preparedStatement;
private Session session = null;
...
executorService = MoreExecutors.listeningDecorator(Executors.newFixedThreadPool(POOL_SIZE));
...
public void writeValue(Tuple tuple) {
ListenableFuture<String> future = executorService.submit(new Callable<String>() {
@Override
public String call() throws Exception {
if(session == null) {
session = getCluster().connect("dbname");
preparedStatement = session.prepare(queryString);
}
try {
BoundStatement boundStatement = preparedStatement.bind(tuple values);
session.execute(boundStatement);
} catch(Exception exception) {
// handle exception
}
return null;
}
});
私有静态集群集群=null;
私人监听执行服务;
私人编制的报表;
私有会话=null;
...
executorService=MoreExecutors.ListingDecorator(Executors.newFixedThreadPool(池大小));
...
公共void writeValue(元组){
ListenableFuture=executorService.submit(new Callable()){
@凌驾
公共字符串调用()引发异常{
if(会话==null){
session=getCluster().connect(“dbname”);
preparedStatement=session.prepare(查询字符串);
}
试一试{
BoundStatement BoundStatement=preparedStatement.bind(元组值);
session.execute(boundStatement);
}捕获(异常){
//处理异常
}
返回null;
}
});
如果我将“池大小”设置为1,一切正常。如果我将池大小设置为>1,我会得到如下错误:
private static Cluster cluster = null;
private ListeningExecutorService executorService;
private PreparedStatement preparedStatement;
private Session session = null;
...
executorService = MoreExecutors.listeningDecorator(Executors.newFixedThreadPool(POOL_SIZE));
...
public void writeValue(Tuple tuple) {
ListenableFuture<String> future = executorService.submit(new Callable<String>() {
@Override
public String call() throws Exception {
if(session == null) {
session = getCluster().connect("dbname");
preparedStatement = session.prepare(queryString);
}
try {
BoundStatement boundStatement = preparedStatement.bind(tuple values);
session.execute(boundStatement);
} catch(Exception exception) {
// handle exception
}
return null;
}
});
原因:com.datastax.driver.core.exceptions.InvalidQueryException:试图执行未知的准备好的查询:0x75c5b41b9f07afa5384a69790503f963。您可能使用了使用其他群集实例创建的PreparedStatement
因此,我将session
和preparedStatement
放入本地变量。然后,我会收到关于重新准备已准备好的查询的警告…
并且每次都会创建一个新会话
我希望尽可能地重复使用。我做错了什么?我的选择是什么
使这个类成为静态类会有帮助吗?这里有各种竞争条件,执行不是线程安全的
集群
、会话
和PreparedStatement
中的每一个都是应用范围内的单例,即,您只需要一个(对于PreparedStatement
的每个查询一个)
但是,您正在重新创建一个会话
,并可能多次准备PreparedStatement
不要。在构造函数或某个只运行一次的位置初始化一次会话
,同时准备语句。然后在适当的情况下使用会话
和准备语句
使用单线程执行器,一切都像同步一样运行
session.prepare(queryString);
同时。或您在此处使用的PreparedStatement
BoundStatement boundStatement = preparedStatement.bind(tuple values);
session.execute(boundStatement);
可能与您初始化的不同
preparedStatement = session.prepare(queryString);
甚至在同一执行线程内。或者您可能正试图使用与初始化会话不同的会话执行PreparedStatement
这里有各种各样的竞争条件,执行不是线程安全的
集群
、会话
和PreparedStatement
中的每一个都是应用范围内的单例,即,您只需要一个(对于PreparedStatement
的每个查询一个)
但是,您正在重新创建一个会话
,并可能多次准备PreparedStatement
不要。在构造函数或某个只运行一次的位置初始化一次会话
,同时准备语句。然后在适当的情况下使用会话
和准备语句
使用单线程执行器,一切都像同步一样运行
session.prepare(queryString);
同时。或您在此处使用的PreparedStatement
BoundStatement boundStatement = preparedStatement.bind(tuple values);
session.execute(boundStatement);
可能与您初始化的不同
preparedStatement = session.prepare(queryString);
甚至在同一执行线程内。或者您可能正试图使用与初始化会话不同的会话执行PreparedStatement
您可能还希望使用驱动程序的异步API。与其调用
execute
(这将在查询期间阻塞线程),不如调用executeAsync
,并在生成的将来注册回调以处理结果
如果该回调非常昂贵,并且您不想阻止驱动程序的内部I/O线程,那么您可以提供自己的执行器:
ListenableFuture<ResultSet> future = session.executeAsync(statement);
Futures.addCallback(future, new FutureCallback<ResultSet>() {
public void onSuccess(ResultSet rs) { ... }
public void onFailure(Throwable t) { ... }
},
executorService);
ListenableFuture=session.executeAsync(语句);
Futures.addCallback(future,newfuturecallback(){
成功时公共无效(结果集rs){…}
失败时公共无效(可丢弃的t){…}
},
执行人服务);
文档中有一些关于异步编程的提示。您可能还想使用驱动程序的异步API。不要调用
execute
(这将在查询期间阻塞线程),而是调用exe