Cassandra Csharp驱动程序中准备好的语句缓存问题

我相信我发现了如何在Cassandra csharp驱动程序(版本2.7.3)的StatementFactory中缓存预准备语句的逻辑错误。 这是用例。

Guid key = Guid.NewGuid(); // your key ISession session_foo = new Session("foo"); //This is pseudo code ISession session_bar = new Session("bar"); var foo_mapper = new Mapper(session_foo); //table foo_bar var bar_mapper = new Mapper(session_bar); //table foo_bar await Task.WhenAll( foo_mapper.DeleteAsync("WHERE id = ?", key), bar_mapper.DeleteAsync("WHERE id = ?", key)); 

我们发现在运行此删除后,只有第一个请求成功。 在使用StatementFactory的源代码后潜水

 public Task GetStatementAsync(ISession session, Cql cql) { if (cql.QueryOptions.NoPrepare) { // Use a SimpleStatement if we're not supposed to prepare Statement statement = new SimpleStatement(cql.Statement, cql.Arguments); SetStatementProperties(statement, cql); return TaskHelper.ToTask(statement); } return _statementCache .GetOrAdd(cql.Statement, session.PrepareAsync) .Continue(t => { if (_statementCache.Count > MaxPreparedStatementsThreshold) { Logger.Warning(String.Format("The prepared statement cache contains {0} queries. Use parameter markers for queries. You can configure this warning threshold using MappingConfiguration.SetMaxStatementPreparedThreshold() method.", _statementCache.Count)); } Statement boundStatement = t.Result.Bind(cql.Arguments); SetStatementProperties(boundStatement, cql); return boundStatement; }); } 

您可以看到缓存仅使用cql语句。 在我们的例子中,我们在不同的键空间(也称为会话)中具有相同的表名。 我们在两个查询中的cql语句看起来都一样。 即DELETE FROM foo_bar WHERE id =?

如果我不得不猜测,我会说一个简单的解决方法是将cql语句和键空间组合在一起作为缓存键。

有没有其他人遇到过这个问题?

作为一个简单的解决方法,我使用DoNotPrepare跳过缓存

 await _mapper.DeleteAsync(Cql.New("WHERE id = ?", key).WithOptions(opt => opt.DoNotPrepare())); 

我还发现了Datastax的一个未解决的问题

有一个打开的票证可以解决此问题 。

作为解决方法,您可以在创建Mapper时使用不同的MappingConfiguration实例:

 ISession session1 = cluster.Connect("ks1"); ISession session2 = cluster.Connect("ks2"); IMapper mapper1 = new Mapper(session1, new MappingConfiguration()); IMapper mapper2 = new Mapper(session2, new MappingConfiguration()); 

或者,您可以重用单个ISession实例并对查询进行完全限定以包含键空间。

 MappingConfiguration.Global.Define( new Map() .TableName("foo") .KeyspaceName("ks1"), new Map() .TableName("bar") .KeyspaceName("ks2")); ISession session = cluster.Connect(); IMapper mapper = new Mapper(session);