Java 使用 Datastax Cassandra 驱动程序时重新使用 PreparedStatement?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/22915840/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Re-using PreparedStatement when using Datastax Cassandra Driver?
提问by TinusSky
I'm currently using the Datastax Cassandra driver for Cassandra 2 to execute cql3. This works correctly. I started using PreparedStatement's
:
我目前正在使用 Cassandra 2 的 Datastax Cassandra 驱动程序来执行 cql3。这工作正常。我开始使用PreparedStatement's
:
Session session = sessionProvider.getSession();
try {
PreparedStatement ps = session.prepare(cql);
ResultSet rs = session.execute(ps.bind(objects));
if (irsr != null) {
irsr.read(rs);
}
}
Sometimes I get a warning from the driver in my log:
有时我会在日志中收到驱动程序的警告:
Re-preparing already prepared query . Please note that preparing the same query more than once is generally an anti-pattern and will likely affect performance. Consider preparing the statement only once.
This warning makes sense, but i'm not sure how i should reuse the PreparedStatement
?
这个警告是有道理的,但我不确定我应该如何重用PreparedStatement
?
Should I just create all my PreparedStatement
in a constructor/init method and than simply use them?
我应该PreparedStatement
在构造函数/init 方法中创建我的所有内容而不是简单地使用它们吗?
But does this go well when multiple threads use the same PreparedStatement
at the same time (especially calling PreparedStatement.bind()
to bind objects)
但是当多个线程同时使用相同的线程PreparedStatement
(尤其是调用PreparedStatement.bind()
绑定对象)时,这是否顺利?
采纳答案by Daniel S.
You may just initialize the PreparedStatement once and cache it while the app is running. It should be available for use as long as the Cassandra cluster is up.
您可以只初始化 PreparedStatement 一次并在应用程序运行时缓存它。只要 Cassandra 集群启动,它就应该可以使用。
Using the statement from multiple threads is fine (as long as you don't modify it throught setXXX()
methods). When you call bind(), the code underneath only reads the PreparedStatement and then creates a new instance of BoundStatement() which the caller thread is then free to mutate.
使用来自多个线程的语句很好(只要您不通过setXXX()
方法修改它)。当您调用 bind() 时,下面的代码只读取 PreparedStatement,然后创建一个 BoundStatement() 的新实例,然后调用者线程可以自由地改变它。
Here is the source code, if you're curious (search for bind()
).
这是源代码,如果您好奇(搜索bind()
)。
回答by ftrujillo
We are using cassandra in a webapplication with Spring. In our case we create the PreparedStatements when the bean which encapsulate the operation against on cf (our repository) is instatiated.
我们在带有 Spring 的 Web 应用程序中使用 cassandra。在我们的例子中,当封装对 cf(我们的存储库)的操作的 bean 被初始化时,我们创建 PreparedStatements。
Here you have a snippet of the code we are using:
这里有我们正在使用的代码片段:
@Repository
public class StatsRepositoryImpl implements StatsRepository {
@SuppressWarnings("unused")
@PostConstruct
private void initStatements(){
if (cassandraSession == null){
LOG.error("Cassandra 2.0 not available");
} else {
GETSTATS_BY_PROJECT = cassandraSession.prepare(SELECTSTATS+" WHERE projectid = ?");
}
}
@Override
public Stats findByProject(Project project) {
Stats stats = null;
BoundStatement boundStatement = new BoundStatement(GETSTATS_BY_PROJECT);
ResultSet rs = cassandraSession.execute(boundStatement.bind(project.getId()));
for (Row row : rs){
stats = mapRowToStats(row);
}
return stats;
}
By this way the prepared statements are reused each time we execute the method findByProject.
通过这种方式,每次我们执行 findByProject 方法时都会重用准备好的语句。
回答by Harvinder Singh
The above solution will work in case the key space is fixed. In case of multi-tenant scenario, this solution will not suffice. I simply did in the following way, where keyspace is passed as a argument.
如果密钥空间是固定的,上述解决方案将起作用。在多租户场景的情况下,此解决方案是不够的。我只是按照以下方式进行,其中键空间作为参数传递。
Check for keyspace from the prepared statement, if it is same as passed argument then do not prepare the statement as it is already prepared in this case.
检查准备好的语句中的键空间,如果它与传递的参数相同,则不要准备该语句,因为在这种情况下它已经准备好了。
private BatchStatement eventBatch(List<SomeEvent> events, String keySpace) {
BatchStatement batch = new BatchStatement();
String preparedStmtKeySpace = propEventPer == null? "" : propEventPer.getQueryKeyspace();
if(!keySpace.equals("\"" + preparedStmtKeySpace + "\"")) {
eventStmt = cassandraOperations.getSession().prepare(colFamilyInsert(keySpace + "." + "table_name"));
}
....
private RegularStatement colFamilyInsert(String colFamilyName) {
return insertInto(colFamilyName)
.value(PERSON_ID, bindMarker())
.value(DAY, bindMarker());
}
回答by harish
03-Apr-2017 10:02:24,120 WARN [com.datastax.driver.core.Cluster] (cluster1-worker-2851) Re-preparing already prepared query is generally an anti-pattern and will likely affect performance. Consider preparing the statement only once. Query='select * from xxxx where cjpid=? and cjpsnapshotid =?'
Create a pool of PreparedStatement objects, one for each CQL query.
创建一个 PreparedStatement 对象池,每个 CQL 查询一个。
Then, when these queries are being requested by client, fetch the respective cached PS object and supply values by calling bind()
.
然后,当客户端请求这些查询时,通过调用 获取相应的缓存 PS 对象并提供值bind()
。
as explained by Daniel, bind()
does new BoundStmt(param)
which makes this thread safe.
由丹尼尔解释说,bind()
做new BoundStmt(param)
这使得这个线程安全的。