Java8升级至Java17后Cassandra预查询报InvalidQueryException问题
问题详情
报错信息:
com.datastax.driver.core.exceptions.InvalidQueryException: Tried to execute unknown prepared query . You may have used a PreparedStatement that was created with another Cluster instance
升级背景:应用从Java 8迁移至Java 17,当前使用datastax driver core 3.3.0,搭配Cassandra 3.11.7服务器。
相关执行代码:
private ResultSet execute(BoundStatement boundStatement) { queryLogger.debug("Executing : {}", boundStatement.preparedStatement().getQueryString()); ResultSet resultSet = getSession(boundStatement).execute(boundStatement); return resultSet; }
Session获取逻辑:
private Session getSession(BoundStatement boundStatement) { return cassandraConfiguration.getSession(boundStatement.preparedStatement().getQueryKeyspace()); } public Session getSession(String keyspace) { if (!sessionCache.containsKey(keyspace)) { sessionCache.put(keyspace, createSession(keyspace)); } return sessionCache.get(keyspace); }
问题根源
Datastax Driver的PreparedStatement与创建它的Cluster/Session实例强绑定——每个Cluster实例会维护独立的预查询ID映射,跨Cluster实例的Session无法识别其他Cluster创建的PreparedStatement。
Java 17升级后触发该问题,大概率是因为Java 17的类加载、并发模型变化,导致createSession(keyspace)方法无意中创建了多个独立的Cluster实例,这些Session被缓存复用后,就出现了PreparedStatement和执行Session不属于同一Cluster的冲突(Java 8环境下可能因类加载或并发逻辑未触发该矛盾)。
解决步骤
强制复用单Cluster实例
Cluster是重量级资源,必须全局单例,绝不能为每个keyspace新建Cluster。检查createSession(keyspace)实现,确保所有Session都从同一个Cluster实例创建。对齐PreparedStatement与Session的归属
确保执行用的Session,和创建该PreparedStatement的Session属于同一个Cluster实例。要么在目标Session上创建PreparedStatement,要么统一所有Session的Cluster来源。修正Session缓存逻辑
避免因Cluster实例重复创建导致的Session归属混乱,示例优化后的Session获取逻辑:// 全局单例Cluster,初始化一次复用 private static final Cluster CASSANDRA_CLUSTER = Cluster.builder() .addContactPoints("cassandra-host1", "cassandra-host2") .withCredentials("username", "password") .build(); public Session getSession(String keyspace) { if (!sessionCache.containsKey(keyspace)) { // 从单例Cluster创建指定keyspace的Session Session session = CASSANDRA_CLUSTER.connect(keyspace); sessionCache.put(keyspace, session); } return sessionCache.get(keyspace); }升级Datastax Driver版本(推荐)
3.3.0是2018年的老版本,对Java 17的兼容性有限。建议升级到3.x系列的最新稳定版(如3.11.4),该版本兼容Cassandra 3.11.x,同时修复了大量JDK版本升级后的兼容性问题。
内容的提问来源于stack exchange,提问作者Nayaz J H

