1/* 2Copyright 2017 Google LLC 3 4Licensed under the Apache License, Version 2.0 (the "License"); 5you may not use this file except in compliance with the License. 6You may obtain a copy of the License at 7 8 http://www.apache.org/licenses/LICENSE-2.0 9 10Unless required by applicable law or agreed to in writing, software 11distributed under the License is distributed on an "AS IS" BASIS, 12WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13See the License for the specific language governing permissions and 14limitations under the License. 15*/ 16 17/* 18Package spanner provides a client for reading and writing to Cloud Spanner 19databases. See the packages under admin for clients that operate on databases 20and instances. 21 22See https://cloud.google.com/spanner/docs/getting-started/go/ for an 23introduction to Cloud Spanner and additional help on using this API. 24 25See https://godoc.org/cloud.google.com/go for authentication, timeouts, 26connection pooling and similar aspects of this package. 27 28 29Creating a Client 30 31To start working with this package, create a client that refers to the database 32of interest: 33 34 ctx := context.Background() 35 client, err := spanner.NewClient(ctx, "projects/P/instances/I/databases/D") 36 if err != nil { 37 // TODO: Handle error. 38 } 39 defer client.Close() 40 41Remember to close the client after use to free up the sessions in the session 42pool. 43 44 45Simple Reads and Writes 46 47Two Client methods, Apply and Single, work well for simple reads and writes. As 48a quick introduction, here we write a new row to the database and read it back: 49 50 _, err := client.Apply(ctx, []*spanner.Mutation{ 51 spanner.Insert("Users", 52 []string{"name", "email"}, 53 []interface{}{"alice", "a@example.com"})}) 54 if err != nil { 55 // TODO: Handle error. 56 } 57 row, err := client.Single().ReadRow(ctx, "Users", 58 spanner.Key{"alice"}, []string{"email"}) 59 if err != nil { 60 // TODO: Handle error. 61 } 62 63All the methods used above are discussed in more detail below. 64 65 66Keys 67 68Every Cloud Spanner row has a unique key, composed of one or more columns. 69Construct keys with a literal of type Key: 70 71 key1 := spanner.Key{"alice"} 72 73 74KeyRanges 75 76The keys of a Cloud Spanner table are ordered. You can specify ranges of keys 77using the KeyRange type: 78 79 kr1 := spanner.KeyRange{Start: key1, End: key2} 80 81By default, a KeyRange includes its start key but not its end key. Use 82the Kind field to specify other boundary conditions: 83 84 // include both keys 85 kr2 := spanner.KeyRange{Start: key1, End: key2, Kind: spanner.ClosedClosed} 86 87 88KeySets 89 90A KeySet represents a set of keys. A single Key or KeyRange can act as a KeySet. 91Use the KeySets function to build the union of several KeySets: 92 93 ks1 := spanner.KeySets(key1, key2, kr1, kr2) 94 95AllKeys returns a KeySet that refers to all the keys in a table: 96 97 ks2 := spanner.AllKeys() 98 99 100Transactions 101 102All Cloud Spanner reads and writes occur inside transactions. There are two 103types of transactions, read-only and read-write. Read-only transactions cannot 104change the database, do not acquire locks, and may access either the current 105database state or states in the past. Read-write transactions can read the 106database before writing to it, and always apply to the most recent database 107state. 108 109 110Single Reads 111 112The simplest and fastest transaction is a ReadOnlyTransaction that supports a 113single read operation. Use Client.Single to create such a transaction. You can 114chain the call to Single with a call to a Read method. 115 116When you only want one row whose key you know, use ReadRow. Provide the table 117name, key, and the columns you want to read: 118 119 row, err := client.Single().ReadRow(ctx, "Accounts", spanner.Key{"alice"}, []string{"balance"}) 120 121Read multiple rows with the Read method. It takes a table name, KeySet, and list 122of columns: 123 124 iter := client.Single().Read(ctx, "Accounts", keyset1, columns) 125 126Read returns a RowIterator. You can call the Do method on the iterator and pass 127a callback: 128 129 err := iter.Do(func(row *Row) error { 130 // TODO: use row 131 return nil 132 }) 133 134RowIterator also follows the standard pattern for the Google 135Cloud Client Libraries: 136 137 defer iter.Stop() 138 for { 139 row, err := iter.Next() 140 if err == iterator.Done { 141 break 142 } 143 if err != nil { 144 // TODO: Handle error. 145 } 146 // TODO: use row 147 } 148 149Always call Stop when you finish using an iterator this way, whether or not you 150iterate to the end. (Failing to call Stop could lead you to exhaust the 151database's session quota.) 152 153To read rows with an index, use ReadUsingIndex. 154 155Statements 156 157The most general form of reading uses SQL statements. Construct a Statement 158with NewStatement, setting any parameters using the Statement's Params map: 159 160 stmt := spanner.NewStatement("SELECT First, Last FROM SINGERS WHERE Last >= @start") 161 stmt.Params["start"] = "Dylan" 162 163You can also construct a Statement directly with a struct literal, providing 164your own map of parameters. 165 166Use the Query method to run the statement and obtain an iterator: 167 168 iter := client.Single().Query(ctx, stmt) 169 170 171Rows 172 173Once you have a Row, via an iterator or a call to ReadRow, you can extract 174column values in several ways. Pass in a pointer to a Go variable of the 175appropriate type when you extract a value. 176 177You can extract by column position or name: 178 179 err := row.Column(0, &name) 180 err = row.ColumnByName("balance", &balance) 181 182You can extract all the columns at once: 183 184 err = row.Columns(&name, &balance) 185 186Or you can define a Go struct that corresponds to your columns, and extract 187into that: 188 189 var s struct { Name string; Balance int64 } 190 err = row.ToStruct(&s) 191 192 193For Cloud Spanner columns that may contain NULL, use one of the NullXXX types, 194like NullString: 195 196 var ns spanner.NullString 197 if err := row.Column(0, &ns); err != nil { 198 // TODO: Handle error. 199 } 200 if ns.Valid { 201 fmt.Println(ns.StringVal) 202 } else { 203 fmt.Println("column is NULL") 204 } 205 206 207Multiple Reads 208 209To perform more than one read in a transaction, use ReadOnlyTransaction: 210 211 txn := client.ReadOnlyTransaction() 212 defer txn.Close() 213 iter := txn.Query(ctx, stmt1) 214 // ... 215 iter = txn.Query(ctx, stmt2) 216 // ... 217 218You must call Close when you are done with the transaction. 219 220 221Timestamps and Timestamp Bounds 222 223Cloud Spanner read-only transactions conceptually perform all their reads at a 224single moment in time, called the transaction's read timestamp. Once a read has 225started, you can call ReadOnlyTransaction's Timestamp method to obtain the read 226timestamp. 227 228By default, a transaction will pick the most recent time (a time where all 229previously committed transactions are visible) for its reads. This provides the 230freshest data, but may involve some delay. You can often get a quicker response 231if you are willing to tolerate "stale" data. You can control the read timestamp 232selected by a transaction by calling the WithTimestampBound method on the 233transaction before using it. For example, to perform a query on data that is at 234most one minute stale, use 235 236 client.Single(). 237 WithTimestampBound(spanner.MaxStaleness(1*time.Minute)). 238 Query(ctx, stmt) 239 240See the documentation of TimestampBound for more details. 241 242 243Mutations 244 245To write values to a Cloud Spanner database, construct a Mutation. The spanner 246package has functions for inserting, updating and deleting rows. Except for the 247Delete methods, which take a Key or KeyRange, each mutation-building function 248comes in three varieties. 249 250One takes lists of columns and values along with the table name: 251 252 m1 := spanner.Insert("Users", 253 []string{"name", "email"}, 254 []interface{}{"alice", "a@example.com"}) 255 256One takes a map from column names to values: 257 258 m2 := spanner.InsertMap("Users", map[string]interface{}{ 259 "name": "alice", 260 "email": "a@example.com", 261 }) 262 263And the third accepts a struct value, and determines the columns from the 264struct field names: 265 266 type User struct { Name, Email string } 267 u := User{Name: "alice", Email: "a@example.com"} 268 m3, err := spanner.InsertStruct("Users", u) 269 270 271Writes 272 273To apply a list of mutations to the database, use Apply: 274 275 _, err := client.Apply(ctx, []*spanner.Mutation{m1, m2, m3}) 276 277If you need to read before writing in a single transaction, use a 278ReadWriteTransaction. ReadWriteTransactions may be aborted automatically by the 279backend and need to be retried. You pass in a function to ReadWriteTransaction, 280and the client will handle the retries automatically. Use the transaction's 281BufferWrite method to buffer mutations, which will all be executed at the end 282of the transaction: 283 284 _, err := client.ReadWriteTransaction(ctx, func(ctx context.Context, txn *spanner.ReadWriteTransaction) error { 285 var balance int64 286 row, err := txn.ReadRow(ctx, "Accounts", spanner.Key{"alice"}, []string{"balance"}) 287 if err != nil { 288 // The transaction function will be called again if the error code 289 // of this error is Aborted. The backend may automatically abort 290 // any read/write transaction if it detects a deadlock or other 291 // problems. 292 return err 293 } 294 if err := row.Column(0, &balance); err != nil { 295 return err 296 } 297 298 if balance <= 10 { 299 return errors.New("insufficient funds in account") 300 } 301 balance -= 10 302 m := spanner.Update("Accounts", []string{"user", "balance"}, []interface{}{"alice", balance}) 303 txn.BufferWrite([]*spanner.Mutation{m}) 304 305 // The buffered mutation will be committed. If the commit 306 // fails with an Aborted error, this function will be called 307 // again. 308 return nil 309 }) 310 311 312Structs 313 314Cloud Spanner STRUCT (aka STRUCT) values 315(https://cloud.google.com/spanner/docs/data-types#struct-type) can be 316represented by a Go struct value. 317 318A proto StructType is built from the field types and field tag information of 319the Go struct. If a field in the struct type definition has a 320"spanner:<field_name>" tag, then the value of the "spanner" key in the tag is 321used as the name for that field in the built StructType, otherwise the field 322name in the struct definition is used. To specify a field with an empty field 323name in a Cloud Spanner STRUCT type, use the `spanner:""` tag annotation against 324the corresponding field in the Go struct's type definition. 325 326A STRUCT value can contain STRUCT-typed and Array-of-STRUCT typed fields and 327these can be specified using named struct-typed and []struct-typed fields inside 328a Go struct. However, embedded struct fields are not allowed. Unexported struct 329fields are ignored. 330 331NULL STRUCT values in Cloud Spanner are typed. A nil pointer to a Go struct 332value can be used to specify a NULL STRUCT value of the corresponding 333StructType. Nil and empty slices of a Go STRUCT type can be used to specify 334NULL and empty array values respectively of the corresponding StructType. A 335slice of pointers to a Go struct type can be used to specify an array of 336NULL-able STRUCT values. 337 338 339DML and Partitioned DML 340 341Spanner supports DML statements like INSERT, UPDATE and DELETE. Use 342ReadWriteTransaction.Update to run DML statements. It returns the number of rows 343affected. (You can call use ReadWriteTransaction.Query with a DML statement. The 344first call to Next on the resulting RowIterator will return iterator.Done, and 345the RowCount field of the iterator will hold the number of affected rows.) 346 347For large databases, it may be more efficient to partition the DML statement. 348Use client.PartitionedUpdate to run a DML statement in this way. Not all DML 349statements can be partitioned. 350 351 352Tracing 353 354This client has been instrumented to use OpenCensus tracing 355(http://opencensus.io). To enable tracing, see "Enabling Tracing for a Program" 356at https://godoc.org/go.opencensus.io/trace. OpenCensus tracing requires Go 1.8 357or higher. 358*/ 359package spanner // import "cloud.google.com/go/spanner" 360