func (s *Session) CommitReadWriteTransaction() (spanner.CommitResponse, error) {
	if !s.InReadWriteTransaction() {
		return spanner.CommitResponse{}, errors.New("read-write transaction is not running")
	}
	s.tcMutex.Lock()
	defer s.tcMutex.Unlock()
	resp, err := s.tc.rwTxn.CommitWithReturnResp(s.ctx)
	s.tc = nil
	return resp, err
}
CommitReadWriteTransaction commits read-write transaction and returns commit timestamp if successful.
package main
import (
	"context"
	"errors"
	"fmt"
	"sync"
	"time"
	"cloud.google.com/go/spanner"
	"google.golang.org/api/option"
	"google.golang.org/grpc/codes"
	adminapi "cloud.google.com/go/spanner/admin/database/apiv1"
	pb "google.golang.org/genproto/googleapis/spanner/v1"
)
var clientConfig = spanner.ClientConfig{
	SessionPoolConfig: spanner.SessionPoolConfig{
		MinOpened: 1,
		MaxOpened: 10,  
	},
}
var defaultClientOpts = []option.ClientOption{
	option.WithGRPCConnectionPool(1),
}
const defaultPriority = pb.RequestOptions_PRIORITY_MEDIUM
type Session struct {
	ctx             context.Context
	projectId       string
	instanceId      string
	databaseId      string
	client          *spanner.Client
	adminClient     *adminapi.DatabaseAdminClient
	clientOpts      []option.ClientOption
	defaultPriority pb.RequestOptions_Priority
	tc              *transactionContext
	tcMutex         sync.Mutex  
}
type transactionContext struct {
	priority      pb.RequestOptions_Priority
	sendHeartbeat bool  
	rwTxn         *spanner.ReadWriteStmtBasedTransaction
	roTxn         *spanner.ReadOnlyTransaction
}
func NewSession(ctx context.Context, projectId string, instanceId string, databaseId string, priority pb.RequestOptions_Priority, opts ...option.ClientOption) (*Session, error) {
	dbPath := fmt.Sprintf("projects/%s/instances/%s/databases/%s", projectId, instanceId, databaseId)
	opts = append(opts, defaultClientOpts...)
	client, err := spanner.NewClientWithConfig(ctx, dbPath, clientConfig, opts...)
	if err != nil {
		return nil, err
	}
	adminClient, err := adminapi.NewDatabaseAdminClient(ctx, opts...)
	if err != nil {
		return nil, err
	}
	if priority == pb.RequestOptions_PRIORITY_UNSPECIFIED {
		priority = defaultPriority
	}
	session := &Session{
		ctx:             ctx,
		projectId:       projectId,
		instanceId:      instanceId,
		databaseId:      databaseId,
		client:          client,
		clientOpts:      opts,
		adminClient:     adminClient,
		defaultPriority: priority,
	}
	go session.startHeartbeat()
	return session, nil
}
func (s *Session) InReadWriteTransaction() bool {
	return s.tc != nil && s.tc.rwTxn != nil
}
func (s *Session) InReadOnlyTransaction() bool {
	return s.tc != nil && s.tc.roTxn != nil
}
func (s *Session) BeginReadWriteTransaction(priority pb.RequestOptions_Priority) error {
	if s.InReadWriteTransaction() {
		return errors.New("read-write transaction is already running")
	}
	if priority == pb.RequestOptions_PRIORITY_UNSPECIFIED {
		priority = s.defaultPriority
	}
	opts := spanner.TransactionOptions{
		CommitOptions:  spanner.CommitOptions{ReturnCommitStats: true},
		CommitPriority: priority,
	}
	txn, err := spanner.NewReadWriteStmtBasedTransactionWithOptions(s.ctx, s.client, opts)
	if err != nil {
		return err
	}
	s.tc = &transactionContext{
		priority: priority,
		rwTxn:    txn,
	}
	return nil
}