0

我在我的 Go 应用程序中使用gocql并尝试解决下面描述的问题。

CREATE TABLE IF NOT EXISTS website.users (
    id            uuid,
    email_address text,
    first_name    text,   
    last_name     text,   
    created_at    timestamp,
    PRIMARY KEY (email_address)
);

此查询将覆盖匹配记录,这是 Cassandra 的预期行为。

INSERT INTO users (id, email_address, first_name, last_name, created_at)
VALUES (?, ?, ?, ?, ?)

为了防止覆盖现有记录,我们可以IF NOT EXISTS在查询结束时使用。

INSERT INTO users (id, email_address, first_name, last_name, created_at)
VALUES (?, ?, ?, ?, ?)
IF NOT EXISTS

但是,我无法知道查询是否影响了数据库中的任何行。不知何故,我需要将“记录存在”消息返回给调用者,但目前不可能。如果有一些特定的东西session.Query(...).Exec()会很有用,但据我所知没有。

如果没有匹配的记录,我在继续之前考虑SELECT过,但是您可以猜到这是不可行的,因为当我在之后编辑新记录时,其他一些操作可能已经使用相同的电子邮件地址编辑了新记录。email_addressINSERTINSERTSELECTINSERT

我们如何处理这种情况?

4

2 回答 2

2

解决方案是使用ScanCAS,库中的测试用例示例在这里

注意

  • 中字段的顺序ScanCAS()应与块cqlsh> DESCRIBE keyspace.users;的输出相匹配CREATE TABLE ...
  • 如果您不关心扫描的字段,请改用 MapScanCAS
func (r Repository) Insert(ctx context.Context, user User) error {
    var (
        emailAddressCAS, firstNameCAS, idCAS, lastNameCAS string
        createdAtCAS                                      time.Time
    )

    query := `
INSERT INTO users (email_address, created_at, first_name, id, last_name)
VALUES (?, ?, ?, ?, ?) IF NOT EXISTS
`

    applied, err := r.session.Query(
        query,
        user.EmailAddress,
        user.CreatedAt,
        user.FirstName,
        user.LastName,
        user.CreateAt,
    ).
    WithContext(ctx).
    ScanCAS(&emailAddressCAS, &createdAtCAS, &firstNameCAS, &idCAS, &lastNameCAS)

    if err != nil {
        return err
    }
    if !applied {
        // Check CAS vars here if you want.
        return // your custom error implying a duplication
    }

    return nil
}
于 2021-01-17T19:54:21.303 回答
1

如果您将 INSERT 与 一起使用IF NOT EXISTS,则与不返回任何内容的“正常”插入相比,此类查询返回单行结果,其中包括:

  • 具有 name[applied]和 true 值的字段 - 如果之前没有记录,并且插入了新行
  • 具有 name[applied]和 false 值的字段 + 现有行的所有列。

因此,您只需要获取插入查询的结果并对其进行分析。有关更多详细信息,请参阅文档

于 2021-01-17T18:05:20.753 回答