当前位置: 首页 > 知识库问答 >
问题:

卡桑德拉·夏普驱动程序中的预准备语句缓存问题

訾安邦
2023-03-14

我相信我已经在Cassandra csharp驱动程序(版本2.7.3)的StatementFactory中发现了一个关于如何缓存准备好的语句的逻辑的bug。下面是使用案例。

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<Foo>("WHERE id = ?", key),
   bar_mapper.DeleteAsync<Bar>("WHERE id = ?", key));

我们发现,运行此删除后,只有第一个请求成功。在深入了解StatementFactory的源代码之后

public Task<Statement> 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 语句看起来是相同的。即从foo_bar中删除 id =?。

如果我必须猜测,我会说一个简单的修复方法是将cql语句和keyspace组合在一起作为缓存键。

以前有没有人遇到过这个问题?

共有2个答案

何勇
2023-03-14

有一张公开的票可以修复这种行为。

作为一种解决方法,您可以在创建< code >映射器时使用不同的< code > mapping configuration 实例:

ISession session1 = cluster.Connect("ks1");
ISession session2 = cluster.Connect("ks2");

IMapper mapper1 = new Mapper(session1, new MappingConfiguration());
IMapper mapper2 = new Mapper(session2, new MappingConfiguration());

或者,您可以重用单个< code > isersion 实例,并完全限定您的查询以包括键空间。

MappingConfiguration.Global.Define(
   new Map<Foo>()
      .TableName("foo")
      .KeyspaceName("ks1"),
   new Map<Bar>()
      .TableName("bar")
      .KeyspaceName("ks2"));

ISession session = cluster.Connect();
IMapper mapper = new Mapper(session);
郭逸清
2023-03-14

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

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

我还发现了一个与数据轴有关的开放问题

 类似资料:
  • 我在Datastax java驱动程序中使用了下面的批处理准备语句代码。 这个Batch语句是已记录还是未记录?

  • 我使用的是datastax Cassandra 2.0驱动程序,我在使用预先准备好的绑定语句。假设我想查询如下内容: 其中,UUID1、UUID2、UUID3是UUID值。使用绑定语句实现这一点的编程方法是什么?目前,我正在尝试以下方法: 这当前返回了错误的结果。如何正确格式化查询有何建议?

  • 我需要一些帮助来定义使用Cassandra的数据堆垛对象映射器和使用预准备语句的常见解决方案之间的区别。而不是代码将对象映射到POJO类会更干净,在性能等方面还有其他优点。.感谢您的回答。

  • 我试图使用datastax中的nodejs驱动程序,在cassandra 2.1.2中向用户定义的类型添加一个字段。我在cqlsh中使用<code>ALTER TYPE</code>添加了该字段。当我试图添加一个包含udt的行,并为新字段添加一个值时,它会以空值插入,而不是我提供的值。我强烈怀疑这与集群缓存准备好的语句的方式有关。因为我记得读到准备好的语句是由查询的哈希索引的,所以我尝试更改查询中

  • 由于基础设施的限制,我们无法将运行的Cassandra版本升级到 Cassandra现在抛出一个 在这种情况下,最好的解决方法是什么?大多数指南告诉我们简单地使用< code>UNSET:(。

  • 我正在尝试运行以下查询 我将Long的Java列表绑定为参数,并得到一个异常 如果我尝试使用(?),它期望绑定单个Long项目,但我需要一个集合 语法有误吗?