本页介绍了如何使用 Spanner 客户端库为单个语句执行设置超时。这可用于替换客户端库的默认超时配置。如果语句无法在给定超时值内完成,则会失败并返回 DEADLINE_EXCEEDED
错误。
以下示例展示了如何在 Cloud Spanner 客户端库中为单个语句执行设置超时。
Go
import (
"context"
"fmt"
"io"
"time"
"cloud.google.com/go/spanner"
"google.golang.org/grpc/codes"
)
func setStatementTimeout(w io.Writer, db string) error {
client, err := spanner.NewClient(context.Background(), db)
if err != nil {
return err
}
defer client.Close()
_, err = client.ReadWriteTransaction(context.Background(),
func(ctx context.Context, txn *spanner.ReadWriteTransaction) error {
// Create a context with a 60-second timeout and apply this timeout to the insert statement.
ctxWithTimeout, cancel := context.WithTimeout(context.Background(), 60*time.Second)
defer cancel()
stmt := spanner.Statement{
SQL: `INSERT Singers (SingerId, FirstName, LastName)
VALUES (39, 'George', 'Washington')`,
}
rowCount, err := txn.Update(ctxWithTimeout, stmt)
// Get the error code from the error. This function returns codes.OK if err == nil.
code := spanner.ErrCode(err)
if code == codes.DeadlineExceeded {
fmt.Fprintf(w, "Insert statement timed out.\n")
} else if code == codes.OK {
fmt.Fprintf(w, "%d record(s) inserted.\n", rowCount)
} else {
fmt.Fprintf(w, "Insert statement failed with error %v\n", err)
}
return err
})
if err != nil {
return err
}
return nil
}
Java
static void executeSqlWithTimeout() {
// TODO(developer): Replace these variables before running the sample.
String projectId = "my-project";
String instanceId = "my-instance";
String databaseId = "my-database";
try (Spanner spanner =
SpannerOptions.newBuilder().setProjectId(projectId).build().getService()) {
DatabaseClient client =
spanner.getDatabaseClient(DatabaseId.of(projectId, instanceId, databaseId));
executeSqlWithTimeout(client);
}
}
static void executeSqlWithTimeout(DatabaseClient client) {
CallContextConfigurator configurator = new CallContextConfigurator() {
public <ReqT, RespT> ApiCallContext configure(ApiCallContext context, ReqT request,
MethodDescriptor<ReqT, RespT> method) {
// DML uses the ExecuteSql RPC.
if (method == SpannerGrpc.getExecuteSqlMethod()) {
// NOTE: You can use a GrpcCallContext to set a custom timeout for a single RPC
// invocation. This timeout can however ONLY BE SHORTER than the default timeout
// for the RPC. If you set a timeout that is longer than the default timeout, then
// the default timeout will be used.
return GrpcCallContext.createDefault()
.withCallOptions(CallOptions.DEFAULT.withDeadlineAfter(60L, TimeUnit.SECONDS));
}
// Return null to indicate that the default should be used for other methods.
return null;
}
};
// Create a context that uses the custom call configuration.
Context context =
Context.current().withValue(SpannerOptions.CALL_CONTEXT_CONFIGURATOR_KEY, configurator);
// Run the transaction in the custom context.
context.run(() ->
client.readWriteTransaction().<long[]>run(transaction -> {
String sql = "INSERT INTO Singers (SingerId, FirstName, LastName)\n"
+ "VALUES (20, 'George', 'Washington')";
long rowCount = transaction.executeUpdate(Statement.of(sql));
System.out.printf("%d record inserted.%n", rowCount);
return null;
})
);
}