tessl install tessl/golang-cloud-google-com--go--spanner@1.87.2Official Google Cloud Spanner client library for Go providing comprehensive database operations, transactions, and admin functionality
This document covers creating, configuring, and managing Spanner clients including session pool configuration and client options.
Create a client with default configuration:
func NewClient(ctx context.Context, database string, opts ...option.ClientOption) (*Client, error)Parameters:
ctx: Context for authentication and connection setupdatabase: Database name in format projects/PROJECT_ID/instances/INSTANCE_ID/databases/DATABASE_IDopts: Optional client options (credentials, endpoints, etc.)Example:
ctx := context.Background()
client, err := spanner.NewClient(ctx, "projects/my-project/instances/my-instance/databases/my-db")
if err != nil {
log.Fatal(err)
}
defer client.Close()Create a client with custom session pool and query options:
func NewClientWithConfig(ctx context.Context, database string, config ClientConfig, opts ...option.ClientOption) (*Client, error)Example:
config := spanner.ClientConfig{
SessionPoolConfig: spanner.SessionPoolConfig{
MinOpened: 50,
MaxOpened: 200,
MaxIdle: 20,
},
QueryOptions: spanner.QueryOptions{
Priority: sppb.RequestOptions_PRIORITY_MEDIUM,
},
}
client, err := spanner.NewClientWithConfig(ctx, database, config)
if err != nil {
log.Fatal(err)
}
defer client.Close()Create a client with multiple endpoint support for failover:
func NewMultiEndpointClient(ctx context.Context, database string, gmeCfg *grpcgcp.GCPMultiEndpointOptions, opts ...option.ClientOption) (*Client, *grpcgcp.GCPMultiEndpoint, error)
func NewMultiEndpointClientWithConfig(ctx context.Context, database string, config ClientConfig, gmeCfg *grpcgcp.GCPMultiEndpointOptions, opts ...option.ClientOption) (*Client, *grpcgcp.GCPMultiEndpoint, error)These functions create a client with GCPMultiEndpoint support for:
type Client struct {
// Has unexported fields
}The Client is safe for concurrent use and provides methods for reading, writing, and managing transactions.
// Data operations
func (c *Client) Single() *ReadOnlyTransaction
func (c *Client) ReadOnlyTransaction() *ReadOnlyTransaction
func (c *Client) ReadWriteTransaction(ctx context.Context, f func(context.Context, *ReadWriteTransaction) error) (commitTimestamp time.Time, err error)
func (c *Client) ReadWriteTransactionWithOptions(ctx context.Context, f func(context.Context, *ReadWriteTransaction) error, options TransactionOptions) (CommitResponse, error)
// Batch operations
func (c *Client) BatchReadOnlyTransaction(ctx context.Context, tb TimestampBound) (*BatchReadOnlyTransaction, error)
func (c *Client) BatchReadOnlyTransactionFromID(tid BatchReadOnlyTransactionID) *BatchReadOnlyTransaction
func (c *Client) BatchWrite(ctx context.Context, mgs []*MutationGroup) *BatchWriteResponseIterator
func (c *Client) BatchWriteWithOptions(ctx context.Context, mgs []*MutationGroup, opts BatchWriteOptions) *BatchWriteResponseIterator
// Write operations
func (c *Client) Apply(ctx context.Context, ms []*Mutation, opts ...ApplyOption) (commitTimestamp time.Time, err error)
func (c *Client) PartitionedUpdate(ctx context.Context, statement Statement) (count int64, err error)
func (c *Client) PartitionedUpdateWithOptions(ctx context.Context, statement Statement, opts QueryOptions) (count int64, err error)
// Management
func (c *Client) Close()
func (c *Client) DatabaseName() string
func (c *Client) ClientID() stringClient lifecycle:
Close() when done to release sessionsdefer client.Close() to ensure cleanupComplete configuration for client behavior:
type ClientConfig struct {
// NumChannels is deprecated - use option.WithGRPCConnectionPool instead
NumChannels int
// Session pool configuration
SessionPoolConfig SessionPoolConfig
// Labels attached to all sessions created by this client
SessionLabels map[string]string
// Default query execution options
QueryOptions QueryOptions
// Default read operation options
ReadOptions ReadOptions
// Default apply operation options
ApplyOptions []ApplyOption
// Default transaction options
TransactionOptions TransactionOptions
// Default batch write options
BatchWriteOptions BatchWriteOptions
// Custom retry settings (overrides defaults)
CallOptions *vkit.CallOptions
// User agent prefix for tracking
UserAgent string
// Database role to assume for all operations
DatabaseRole string
// Disable routing read-write and PDML to leader region
DisableRouteToLeader bool
// Logger for client logging (nil uses standard logger)
Logger *log.Logger
// Compression for gRPC calls ("gzip" or "identity")
Compression string
// Timeout for batch session operations
BatchTimeout time.Duration
// Direct read options for replica/region routing
DirectedReadOptions *sppb.DirectedReadOptions
// OpenTelemetry meter provider
OpenTelemetryMeterProvider metric.MeterProvider
// Enable end-to-end tracing spans at Spanner layer
EnableEndToEndTracing bool
// Disable native metrics emission
DisableNativeMetrics bool
// Internal: experimental host flag
IsExperimentalHost bool
}Configuration for the client's session pool:
type SessionPoolConfig struct {
// Maximum number of opened sessions (blocks when reached)
// Default: NumChannels * 100
MaxOpened uint64
// Minimum number of sessions to maintain
// Default: 100
MinOpened uint64
// Maximum number of idle sessions allowed
// Default: 0
MaxIdle uint64
// MaxBurst is deprecated and no longer used
MaxBurst uint64
// WriteSessions is deprecated and no longer used
WriteSessions float64
// Number of workers for health checking
// Default: 10
HealthCheckWorkers int
// Interval between health checks
// Default: 50 minutes
HealthCheckInterval time.Duration
// Interval for checking multiplexed sessions
// Default: 10 minutes
MultiplexSessionCheckInterval time.Duration
// Track stacktrace of goroutines taking sessions (debugging)
// Default: false
TrackSessionHandles bool
// Configuration for inactive transaction handling
InactiveTransactionRemovalOptions InactiveTransactionRemovalOptions
}Default Session Pool Config:
var DefaultSessionPoolConfig = SessionPoolConfig{
MinOpened: 100,
MaxOpened: numChannels * 100,
MaxBurst: 10,
WriteSessions: 0.2,
HealthCheckWorkers: 10,
HealthCheckInterval: 50 * time.Minute,
InactiveTransactionRemovalOptions: InactiveTransactionRemovalOptions{
ActionOnInactiveTransaction: Warn,
},
}config := spanner.ClientConfig{
SessionPoolConfig: spanner.SessionPoolConfig{
MinOpened: 50, // Keep at least 50 sessions warm
MaxOpened: 400, // Allow up to 400 sessions
MaxIdle: 50, // Expire idle sessions beyond 50
HealthCheckWorkers: 20, // Use 20 workers for health checks
HealthCheckInterval: 30 * time.Minute,
TrackSessionHandles: true, // Enable for debugging leaks
},
}
client, err := spanner.NewClientWithConfig(ctx, database, config)Configuration for handling inactive transactions:
type InactiveTransactionRemovalOptions struct {
// Action to take on inactive transactions
ActionOnInactiveTransaction ActionOnInactiveTransactionKind
// Has unexported fields for thresholds and frequencies
}
type ActionOnInactiveTransactionKind int
const (
NoAction ActionOnInactiveTransactionKind = iota // No action
Warn // Log inactive transactions
Close // Close without logging
WarnAndClose // Log and close
)Default options for SQL queries and DML:
type QueryOptions struct {
// Query execution mode
Mode *sppb.ExecuteSqlRequest_QueryMode
// Query optimizer options
Options *sppb.ExecuteSqlRequest_QueryOptions
// RPC priority for query execution
Priority sppb.RequestOptions_Priority
// Tag for tracking this request
RequestTag string
// Enable Data Boost for partitioned queries
DataBoostEnabled bool
// Direct read options for replica/region targeting
DirectedReadOptions *sppb.DirectedReadOptions
// Exclude partitioned update from change streams
ExcludeTxnFromChangeStreams bool
// Mark statement as last in transaction
LastStatement bool
}Default options for read operations:
type ReadOptions struct {
// Index to use for reading
Index string
// Maximum number of rows to read (0 = no limit)
Limit int
// RPC priority
Priority sppb.RequestOptions_Priority
// Request tag for tracking
RequestTag string
// Enable Data Boost for partitioned reads
DataBoostEnabled bool
// Direct read options for replica/region targeting
DirectedReadOptions *sppb.DirectedReadOptions
// Row ordering control
OrderBy sppb.ReadRequest_OrderBy
// Lock hint for read-write transactions
LockHint sppb.ReadRequest_LockHint
}Options for transaction execution:
type TransactionOptions struct {
// Options for commit operation
CommitOptions CommitOptions
// Tag automatically included with all statements and commit
TransactionTag string
// Priority for the Commit RPC
CommitPriority sppb.RequestOptions_Priority
// Read lock mode for read/write transactions
ReadLockMode sppb.TransactionOptions_ReadWrite_ReadLockMode
// Exclude transaction from change streams
ExcludeTxnFromChangeStreams bool
// Isolation level for read/write transaction
IsolationLevel sppb.TransactionOptions_IsolationLevel
// Controls BeginTransaction RPC behavior
BeginTransactionOption BeginTransactionOption
}
type BeginTransactionOption int
const (
// Use default for transaction type
DefaultBeginTransaction BeginTransactionOption = iota
// Include BeginTransaction with first statement (default for RW)
InlinedBeginTransaction
// Use separate BeginTransaction RPC (default for RO and stmt-based)
ExplicitBeginTransaction
)Options for committing transactions:
type CommitOptions struct {
// Request commit statistics in response
ReturnCommitStats bool
// Maximum delay before commit (for latency optimization)
MaxCommitDelay *time.Duration
}Options for batch write operations:
type BatchWriteOptions struct {
// RPC priority for batch write
Priority sppb.RequestOptions_Priority
// Transaction tag for all transactions in batch
TransactionTag string
// Exclude all transactions from change streams
ExcludeTxnFromChangeStreams bool
}Standard Google API client options can be passed to client constructors:
import "google.golang.org/api/option"
// Custom credentials
client, err := spanner.NewClient(ctx, database,
option.WithCredentialsFile("/path/to/credentials.json"))
// Custom endpoint
client, err := spanner.NewClient(ctx, database,
option.WithEndpoint("custom-endpoint:443"))
// gRPC connection pool
client, err := spanner.NewClient(ctx, database,
option.WithGRPCConnectionPool(8))
// Disable authentication (for emulator)
client, err := spanner.NewClient(ctx, database,
option.WithoutAuthentication())For high-throughput workloads:
config := spanner.ClientConfig{
SessionPoolConfig: spanner.SessionPoolConfig{
MinOpened: 200,
MaxOpened: 1000,
MaxIdle: 100,
HealthCheckWorkers: 50,
},
QueryOptions: spanner.QueryOptions{
Priority: sppb.RequestOptions_PRIORITY_HIGH,
},
Compression: "gzip",
}
client, err := spanner.NewClientWithConfig(ctx, database, config,
option.WithGRPCConnectionPool(16))For read-heavy workloads with stale reads:
config := spanner.ClientConfig{
SessionPoolConfig: spanner.SessionPoolConfig{
MinOpened: 100,
MaxOpened: 500,
MaxIdle: 50,
},
ReadOptions: spanner.ReadOptions{
Priority: sppb.RequestOptions_PRIORITY_MEDIUM,
},
DisableRouteToLeader: true, // Allow reads from replicas
}
client, err := spanner.NewClientWithConfig(ctx, database, config)For debugging session leaks:
config := spanner.ClientConfig{
SessionPoolConfig: spanner.SessionPoolConfig{
MinOpened: 10,
MaxOpened: 50,
TrackSessionHandles: true, // Track goroutines
},
Logger: log.New(os.Stdout, "spanner: ", log.LstdFlags),
}
client, err := spanner.NewClientWithConfig(ctx, database, config)Direct reads to specific regions:
directedReadOptions := &sppb.DirectedReadOptions{
Replicas: &sppb.DirectedReadOptions_IncludeReplicas_{
IncludeReplicas: &sppb.DirectedReadOptions_IncludeReplicas{
ReplicaSelections: []*sppb.DirectedReadOptions_ReplicaSelection{
{
Location: "us-central1",
Type: sppb.DirectedReadOptions_ReplicaSelection_READ_ONLY,
},
},
},
},
}
config := spanner.ClientConfig{
DirectedReadOptions: directedReadOptions,
}
client, err := spanner.NewClientWithConfig(ctx, database, config)Assume a specific database role for all operations:
config := spanner.ClientConfig{
DatabaseRole: "reporting_role",
}
client, err := spanner.NewClientWithConfig(ctx, database, config)
// All operations use reporting_role permissionsfunc EnableOpenTelemetryMetrics()
func IsOpenTelemetryMetricsEnabled() boolEnable before creating clients:
spanner.EnableOpenTelemetryMetrics()
// Configure meter provider
config := spanner.ClientConfig{
OpenTelemetryMeterProvider: myMeterProvider,
EnableEndToEndTracing: true,
}
client, err := spanner.NewClientWithConfig(ctx, database, config)These functions are deprecated - use OpenTelemetry instead:
func EnableStatViews() error
func EnableGfeLatencyView() error
func EnableGfeHeaderMissingCountView() error
func EnableGfeLatencyAndHeaderMissingCountViews() error
func DisableGfeLatencyAndHeaderMissingCountViews()defer client.Close() to avoid session leaksvar client *spanner.Client
func init() {
ctx := context.Background()
var err error
client, err = spanner.NewClient(ctx, database)
if err != nil {
log.Fatal(err)
}
}
func main() {
defer client.Close()
// Use client throughout application
}ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second)
defer cancel()
client, err := spanner.NewClient(ctx, database)
if err != nil {
log.Fatal(err)
}
defer client.Close()import "os"
os.Setenv("SPANNER_EMULATOR_HOST", "localhost:9010")
client, err := spanner.NewClient(ctx, "projects/test/instances/test/databases/test")
// Client automatically connects to emulator