Обратите внимание, что, как поясняется в моем комментарии, я искал что-то чистое, а не транзакцию, поскольку способ работы транзакций немного уродлив (интерфейс должен по крайней мере иметь лямбды в качестве опции, а не анонимные классы: / .) Или лучше, просто beginTransaction (), endTransaction (), например :
this.dbClient.readWriteTransaction()
.run(
new TransactionCallable<Void>() {
@Nullable
@Override
public Void run(TransactionContext transactionContext) throws Exception {
Struct row = transactionContext.readRow(
MY_TABLE,
Key.of(
keyCol1,
keyCol2
),
Collections.singletonList(keyCol1)
);
//this creates a write builder with a bunch of columns
//set to mutated, except for CREATED_ON
WriteBuilder writeBuilder = updateBuilder(
Mutation.newInsertBuilder(MY_TABLE),
myDataModel
);
if(row == null) {
writeBuilder.set(CREATED_ON).to(Timestamp.now()).build();
}
Mutation recMut =
updateBuilder(Mutation.newUpdateBuilder(MY_TABLE), myDataModel).build();
transactionContext.buffer(recMut);
return null;
}
}
);
@ RedPandaCurious - это правильно, ответ Скотта только наполовину работает: (1) обречен на провал, по причинам, изложенным в вопросе, или иначе, просто повторяет то, что я хочу достичь, не иллюстрируя, как ( 2) просто повторяет мой последующий комментарий, не предоставляя никаких подробностей или документов.
@ RedPandaCurious, если вы хотите отметить, что транзакции выполняются быстрее, чем перехват исключений, с некоторыми документами об этом (мне особенно любопытно, если они быстрее, в целом, для различных рабочих нагрузок, несмотря на многие многие параллельные операции, не обязательно просто более быстрые для одного клиента, обрабатывающего исключение), что имеет смысл в качестве ответа. В конце концов, однако, транзакции являются наиболее правильным и разумным способом рассуждать об этом. Вот почему я остановился на этом подходе - так как в любом случае это было некрасиво.
ОК, получается, что если вы удалите аннотацию @Nullable, вы можете использовать лямбда-выражения и, с помощью небольшого дополнительного перефакторинга, уменьшить это значение до:
/**
* Lambda interface for factoring out transactional execution logic
*/
public interface SpannerOperation {
Boolean doOperation(TransactionContext ctxt, Struct row);
}
private Boolean executeIfExists(
... key fields ...
SpannerOperation spannerOperationIfExists,
SpannerOperation spannerOperationifNotExists,
Iterable<String> columns
) {
return this.dbClient.readWriteTransaction().run(
transactionContext -> {
Struct row = transactionContext.readRow(
MY_TABLE,
Key.of(...), //you could even pass the key in as a key
columns
);
if(row != null) {
spannerOperation.doOperation(transactionContext, row);
return true;
} else {
spannerOperationifNotExists.doOperation(transactionContext, null);
return false;
}
}
);
}
public boolean doSomething(... keyStuff.. )
return this.executeIfExists(
.. key fields ...
(ctxt, row) -> {
Mutation mut = Mutation
.newUpdateBuilder(MY_TABLE)
.....//as you like it...
.build()
ctxt.buffer(mut);
return true;
},
(ctxt, row) -> false, //set created_on or whatever
Collections.singleton(..some column you want to read in..)
);
Обратите внимание, что это также работает для таких вещей, как добавление в список и т. Д., И все это сводится к тому, что вам нужно. Google действительно нужен метод ifExists () - я использовал его в нескольких местах ..;)