Возвращает идентификатор строки, созданный CockroachDB после транзакции - PullRequest
1 голос
/ 15 мая 2019

После выполнения транзакции cockroachDB, которая создает строку, я хотел бы вернуть этот идентификатор в мое приложение.

В настоящее время я определяю транзакцию, используя пакет database/sql golang. Затем я использую клиент crdb для выполнения транзакции против CockroachDB.

Я не могу вернуть ничего из транзакции crdb, за исключением ошибки, связанной с самой транзакцией crdb. Как люди извлекают свои последние созданные строки, если интерфейс не предоставляет способ вернуть новый идентификатор строки?

У меня есть транзакция, которая выполняет две вставки. Я получаю результирующие идентификаторы этих вставок и возвращаю ответ с обоими значениями идентификатора.

func myTransaction(ctx context.Context, tx *sql.Tx) (MyTxnResponse, error) {
  var aResult string
  if err := tx.QueryRowContext(ctx, `INSERT INTO foo (a,b,c) VALUES (1,2,3) RETURNING foo_id`).Scan(&aResult); err != nil { ... }

  var bResult string
  if err := tx.QueryRowContext(ctx, `INSERT INTO bar (d,e,f) VALUES (4,5,6) RETURNING bar_id`).Scan(&bResult); err != nil { ... }

  return MyTxnResponse{A: aResult, B: bResult}
}

Теперь я хочу выполнить транзакцию для CRDB

var responseStruct MyTxnResponse
err := crdb.ExecuteTx(ctx.Background(), db, nil, func(tx *sql.Tx) error {
    res, err := myTransaction(ctx,tx)

    // This is what I am currently doing... it seems bad
    responseStruct.A = res.A
    responseStruct.B = res.B

    return err
}
... use responseStruct for something

Я могу получить результат транзакции, используя это внешнее решение var и просто изменяя его состояние в замыкании, но это выглядит как действительно плохая модель. Я уверен, что мне не хватает чего-то, что взорвется мне в лицо, если я сохраню эту схему.

Существует ли стандартный способ возврата чего-либо из транзакции?

1 Ответ

1 голос
/ 15 мая 2019

У вас правильная идея: объявлять переменные вне транзакции и назначать их внутри закрытия транзакции. Это идиоматический способ «возвращать» вещи в Go из замыкания, подобного этому, поскольку единственная альтернатива состоит в том, чтобы функция возвращала interface{}, что потребовало бы приведения во время выполнения, чтобы быть полезным.

Здесь доступно несколько сочетаний клавиш: поскольку responseStruct и res имеют одинаковый тип, вам не нужно перечислять все поля. Вы можете просто сказать responseStruct = res.

Вы можете даже присвоить результат myTransaction непосредственно responseStruct, полностью избегая временного res. Однако вы должны быть осторожны с вашими областями действия переменных - вы не можете использовать :=, потому что это создаст новый responseStruct внутри замыкания. Вместо этого вы должны объявить все другие переменные (здесь err), чтобы вы могли использовать простое = назначение:

var responseStruct MyTxnResponse
err := crdb.ExecuteTx(context.Background(), db, nil, func(tx *sql.Tx) error {
    var err error
    responseStruct, err = myTransaction(ctx, tx)
    return err
})
// use responseStruct (but only if err is nil)
...