func readOnlyTransaction(projectId, instanceId, databaseId string) error {
	ctx := context.Background()
	db, err := sql.Open("spanner", fmt.Sprintf("projects/%s/instances/%s/databases/%s", projectId, instanceId, databaseId))
	if err != nil {
		return err
	}
	defer db.Close()

	// Start a read-only transaction on the Spanner database.
	tx, err := db.BeginTx(ctx, &sql.TxOptions{ReadOnly: true})
	if err != nil {
		return err
	}
	// Committing or rolling back a read-only transaction will not execute an actual Commit or Rollback
	// on the database, but it is needed in order to release the resources that are held by the read-only
	// transaction.
	defer tx.Commit()

	// Verify that the Singers table is empty.
	var c int64
	if err := tx.QueryRowContext(ctx, "SELECT COUNT(*) FROM Singers").Scan(&c); err != nil {
		return err
	}
	fmt.Printf("Singers count is initially %v\n", c)

	// Now insert a new record in the Singers table using an implicit transaction.
	// This change will be applied immediately to the database.
	if _, err := db.ExecContext(ctx, "INSERT INTO Singers (SingerId, Name) VALUES (@id, @name)", int64(1), "Bruce Allison"); err != nil {
		return err
	}

	// The read-only transaction was started before the row was inserted and will continue to read data at a timestamp
	// that was before the row was inserted. It will therefore not see the new record.
	if err := tx.QueryRowContext(ctx, "SELECT COUNT(*) FROM Singers").Scan(&c); err != nil {
		return err
	}
	fmt.Printf("Singers count as seen in the read-only transaction is %v\n", c)

	// Start a new read-only transaction on the Spanner database. This transaction will be started after the new test
	// row was inserted, and the test row should now be visible to the read-only transaction.
	tx, err = db.BeginTx(ctx, &sql.TxOptions{ReadOnly: true})
	if err != nil {
		return err
	}
	defer tx.Commit()
	if err := tx.QueryRowContext(ctx, "SELECT COUNT(*) FROM Singers").Scan(&c); err != nil {
		return err
	}
	fmt.Printf("Singers count in a new read-only transaction is %v\n", c)

	return nil
}
// Sample showing how to execute a read-only transaction on a Spanner database.
//
// Execute the sample with the command `go run main.go` from this directory.
Sample showing how to execute a read-only transaction on a Spanner database.

Execute the sample with the command `go run main.go` from this directory.
// Sample showing how to execute a read - only transaction on a Spanner database . // // Execute the sample with the command ` go run main . go ` from this directory .
func readOnlyTransaction(projectId, instanceId, databaseId string) error {
	ctx := context.Background()
	db, err := sql.Open("spanner", fmt.Sprintf("projects/%s/instances/%s/databases/%s", projectId, instanceId, databaseId))
	if err != nil {
		return err
	}
	defer db.Close()
	tx, err := db.BeginTx(ctx, &sql.TxOptions{ReadOnly: true})
	if err != nil {
		return err
	}
	defer tx.Commit()
	var c int64
	if err := tx.QueryRowContext(ctx, "SELECT COUNT(*) FROM Singers").Scan(&c); err != nil {
		return err
	}
	fmt.Printf("Singers count is initially %v\n", c)
	if _, err := db.ExecContext(ctx, "INSERT INTO Singers (SingerId, Name) VALUES (@id, @name)", int64(1), "Bruce Allison"); err != nil {
		return err
	}
	if err := tx.QueryRowContext(ctx, "SELECT COUNT(*) FROM Singers").Scan(&c); err != nil {
		return err
	}
	fmt.Printf("Singers count as seen in the read-only transaction is %v\n", c)
	tx, err = db.BeginTx(ctx, &sql.TxOptions{ReadOnly: true})
	if err != nil {
		return err
	}
	defer tx.Commit()
	if err := tx.QueryRowContext(ctx, "SELECT COUNT(*) FROM Singers").Scan(&c); err != nil {
		return err
	}
	fmt.Printf("Singers count in a new read-only transaction is %v\n", c)
	return nil
}
func readOnlyTransaction ( projectId , instanceId , databaseId string ) error { ctx := context . Background ( ) db , err := sql . Open ( " " , fmt . Sprintf ( " " , projectId , instanceId , databaseId ) ) if err != nil { return err } defer db . Close ( ) tx , err := db . BeginTx ( ctx , & sql . TxOptions { ReadOnly : true } ) if err != nil { return err } defer tx . Commit ( ) var c int64 if err := tx . QueryRowContext ( ctx , " " ) . Scan ( & c ) ; err != nil { return err } fmt . Printf ( " \n " , c ) if _ , err := db . ExecContext ( ctx , " " , int64 ( 1 ) , " " ) ; err != nil { return err } if err := tx . QueryRowContext ( ctx , " " ) . Scan ( & c ) ; err != nil { return err } fmt . Printf ( " \n " , c ) tx , err = db . BeginTx ( ctx , & sql . TxOptions { ReadOnly : true } ) if err != nil { return err } defer tx . Commit ( ) if err := tx . QueryRowContext ( ctx , " " ) . Scan ( & c ) ; err != nil { return err } fmt . Printf ( " \n " , c ) return nil }
Sample showing how to execute a read-only transaction on a Spanner database.
Sample showing how to execute a read - only transaction on a Spanner database .
// Start a read-only transaction on the Spanner database. // Committing or rolling back a read-only transaction will not execute an actual Commit or Rollback // on the database, but it is needed in order to release the resources that are held by the read-only // transaction. // Verify that the Singers table is empty. // Now insert a new record in the Singers table using an implicit transaction. // This change will be applied immediately to the database. // The read-only transaction was started before the row was inserted and will continue to read data at a timestamp // that was before the row was inserted. It will therefore not see the new record. // Start a new read-only transaction on the Spanner database. This transaction will be started after the new test // row was inserted, and the test row should now be visible to the read-only transaction.