Insert, update, and delete data using mutations

This page describes how to insert, update, and delete data using mutations. A mutation represents a sequence of inserts, updates, and deletes that Spanner applies atomically to different rows and tables in a database. Mutations are designed for writing data. They can't read data from your tables. Many update operations must read existing data before performing modifications. For these use cases, you must use a read-write transaction , which lets Spanner read rows and then apply mutations within the same atomic operation.

Although you can commit mutations by using gRPC or REST , it is more common to access the APIs through the client libraries.

If you need to commit a large number of blind writes, but don't require an atomic transaction, you can bulk modify your Spanner tables using batch write. For more information, see Modify data using batch writes .

Insert new rows in a table

C++

You write data using the InsertMutationBuilder() function. Client::Commit() adds new rows to a table. All inserts in a single batch are applied atomically.

This code shows how to write the data:

  void 
  
 InsertData 
 ( 
 google 
 :: 
 cloud 
 :: 
 spanner 
 :: 
 Client 
  
 client 
 ) 
  
 { 
  
 namespace 
  
 spanner 
  
 = 
  
 :: 
 google 
 :: 
 cloud 
 :: 
 spanner 
 ; 
  
 auto 
  
 insert_singers 
  
 = 
  
 spanner 
 :: 
 InsertMutationBuilder 
 ( 
  
 "Singers" 
 , 
  
 { 
 "SingerId" 
 , 
  
 "FirstName" 
 , 
  
 "LastName" 
 }) 
  
 . 
 EmplaceRow 
 ( 
 1 
 , 
  
 "Marc" 
 , 
  
 "Richards" 
 ) 
  
 . 
 EmplaceRow 
 ( 
 2 
 , 
  
 "Catalina" 
 , 
  
 "Smith" 
 ) 
  
 . 
 EmplaceRow 
 ( 
 3 
 , 
  
 "Alice" 
 , 
  
 "Trentor" 
 ) 
  
 . 
 EmplaceRow 
 ( 
 4 
 , 
  
 "Lea" 
 , 
  
 "Martin" 
 ) 
  
 . 
 EmplaceRow 
 ( 
 5 
 , 
  
 "David" 
 , 
  
 "Lomond" 
 ) 
  
 . 
 Build 
 (); 
  
 auto 
  
 insert_albums 
  
 = 
  
 spanner 
 :: 
 InsertMutationBuilder 
 ( 
  
 "Albums" 
 , 
  
 { 
 "SingerId" 
 , 
  
 "AlbumId" 
 , 
  
 "AlbumTitle" 
 }) 
  
 . 
 EmplaceRow 
 ( 
 1 
 , 
  
 1 
 , 
  
 "Total Junk" 
 ) 
  
 . 
 EmplaceRow 
 ( 
 1 
 , 
  
 2 
 , 
  
 "Go, Go, Go" 
 ) 
  
 . 
 EmplaceRow 
 ( 
 2 
 , 
  
 1 
 , 
  
 "Green" 
 ) 
  
 . 
 EmplaceRow 
 ( 
 2 
 , 
  
 2 
 , 
  
 "Forever Hold Your Peace" 
 ) 
  
 . 
 EmplaceRow 
 ( 
 2 
 , 
  
 3 
 , 
  
 "Terrified" 
 ) 
  
 . 
 Build 
 (); 
  
 auto 
  
 commit_result 
  
 = 
  
 client 
 . 
 Commit 
 ( 
 spanner 
 :: 
 Mutations 
 { 
 insert_singers 
 , 
  
 insert_albums 
 }); 
  
 if 
  
 ( 
 ! 
 commit_result 
 ) 
  
 throw 
  
 std 
 :: 
 move 
 ( 
 commit_result 
 ). 
 status 
 (); 
  
 std 
 :: 
 cout 
 << 
 "Insert was successful [spanner_insert_data] 
 \n 
 " 
 ; 
 } 
 

C#

You can insert data using the connection.CreateInsertCommand() method, which creates a new SpannerCommand to insert rows into a table. The SpannerCommand.ExecuteNonQueryAsync() method adds new rows to the table.

This code shows how to insert data:

  using 
  
  Google.Cloud.Spanner.Data 
 
 ; 
 using 
  
 System 
 ; 
 using 
  
 System.Collections.Generic 
 ; 
 using 
  
 System.Linq 
 ; 
 using 
  
 System.Threading.Tasks 
 ; 
 public 
  
 class 
  
 InsertDataAsyncSample 
 { 
  
 public 
  
 class 
  
 Singer 
  
 { 
  
 public 
  
 int 
  
 SingerId 
  
 { 
  
 get 
 ; 
  
 set 
 ; 
  
 } 
  
 public 
  
 string 
  
 FirstName 
  
 { 
  
 get 
 ; 
  
 set 
 ; 
  
 } 
  
 public 
  
 string 
  
 LastName 
  
 { 
  
 get 
 ; 
  
 set 
 ; 
  
 } 
  
 } 
  
 public 
  
 class 
  
 Album 
  
 { 
  
 public 
  
 int 
  
 SingerId 
  
 { 
  
 get 
 ; 
  
 set 
 ; 
  
 } 
  
 public 
  
 int 
  
 AlbumId 
  
 { 
  
 get 
 ; 
  
 set 
 ; 
  
 } 
  
 public 
  
 string 
  
 AlbumTitle 
  
 { 
  
 get 
 ; 
  
 set 
 ; 
  
 } 
  
 } 
  
 public 
  
 async 
  
 Task 
  
 InsertDataAsync 
 ( 
 string 
  
 projectId 
 , 
  
 string 
  
 instanceId 
 , 
  
 string 
  
 databaseId 
 ) 
  
 { 
  
 string 
  
 connectionString 
  
 = 
  
 $"Data Source=projects/{projectId}/instances/{instanceId}/databases/{databaseId}" 
 ; 
  
 List<Singer> 
  
 singers 
  
 = 
  
 new 
  
 List<Singer> 
  
 { 
  
 new 
  
 Singer 
  
 { 
  
 SingerId 
  
 = 
  
 1 
 , 
  
 FirstName 
  
 = 
  
 "Marc" 
 , 
  
 LastName 
  
 = 
  
 "Richards" 
  
 }, 
  
 new 
  
 Singer 
  
 { 
  
 SingerId 
  
 = 
  
 2 
 , 
  
 FirstName 
  
 = 
  
 "Catalina" 
 , 
  
 LastName 
  
 = 
  
 "Smith" 
  
 }, 
  
 new 
  
 Singer 
  
 { 
  
 SingerId 
  
 = 
  
 3 
 , 
  
 FirstName 
  
 = 
  
 "Alice" 
 , 
  
 LastName 
  
 = 
  
 "Trentor" 
  
 }, 
  
 new 
  
 Singer 
  
 { 
  
 SingerId 
  
 = 
  
 4 
 , 
  
 FirstName 
  
 = 
  
 "Lea" 
 , 
  
 LastName 
  
 = 
  
 "Martin" 
  
 }, 
  
 new 
  
 Singer 
  
 { 
  
 SingerId 
  
 = 
  
 5 
 , 
  
 FirstName 
  
 = 
  
 "David" 
 , 
  
 LastName 
  
 = 
  
 "Lomond" 
  
 }, 
  
 }; 
  
 List<Album> 
  
 albums 
  
 = 
  
 new 
  
 List<Album> 
  
 { 
  
 new 
  
 Album 
  
 { 
  
 SingerId 
  
 = 
  
 1 
 , 
  
 AlbumId 
  
 = 
  
 1 
 , 
  
 AlbumTitle 
  
 = 
  
 "Total Junk" 
  
 }, 
  
 new 
  
 Album 
  
 { 
  
 SingerId 
  
 = 
  
 1 
 , 
  
 AlbumId 
  
 = 
  
 2 
 , 
  
 AlbumTitle 
  
 = 
  
 "Go, Go, Go" 
  
 }, 
  
 new 
  
 Album 
  
 { 
  
 SingerId 
  
 = 
  
 2 
 , 
  
 AlbumId 
  
 = 
  
 1 
 , 
  
 AlbumTitle 
  
 = 
  
 "Green" 
  
 }, 
  
 new 
  
 Album 
  
 { 
  
 SingerId 
  
 = 
  
 2 
 , 
  
 AlbumId 
  
 = 
  
 2 
 , 
  
 AlbumTitle 
  
 = 
  
 "Forever Hold your Peace" 
  
 }, 
  
 new 
  
 Album 
  
 { 
  
 SingerId 
  
 = 
  
 2 
 , 
  
 AlbumId 
  
 = 
  
 3 
 , 
  
 AlbumTitle 
  
 = 
  
 "Terrified" 
  
 }, 
  
 }; 
  
 // Create connection to Cloud Spanner. 
  
 using 
  
 var 
  
 connection 
  
 = 
  
 new 
  
  SpannerConnection 
 
 ( 
 connectionString 
 ); 
  
 await 
  
 connection 
 . 
  OpenAsync 
 
 (); 
  
 await 
  
 connection 
 . 
 RunWithRetriableTransactionAsync 
 ( 
 async 
  
 transaction 
  
 = 
>  
 { 
  
 await 
  
 Task 
 . 
 WhenAll 
 ( 
 singers 
 . 
 Select 
 ( 
 singer 
  
 = 
>  
 { 
  
 // Insert rows into the Singers table. 
  
 using 
  
 var 
  
 cmd 
  
 = 
  
 connection 
 . 
 CreateInsertCommand 
 ( 
 "Singers" 
 , 
  
 new 
  
 SpannerParameterCollection 
  
 { 
  
 { 
  
 "SingerId" 
 , 
  
 SpannerDbType 
 . 
 Int64 
 , 
  
 singer 
 . 
 SingerId 
  
 }, 
  
 { 
  
 "FirstName" 
 , 
  
 SpannerDbType 
 . 
 String 
 , 
  
 singer 
 . 
 FirstName 
  
 }, 
  
 { 
  
 "LastName" 
 , 
  
 SpannerDbType 
 . 
 String 
 , 
  
 singer 
 . 
 LastName 
  
 } 
  
 }); 
  
 cmd 
 . 
 Transaction 
  
 = 
  
 transaction 
 ; 
  
 return 
  
 cmd 
 . 
 ExecuteNonQueryAsync 
 (); 
  
 })); 
  
 await 
  
 Task 
 . 
 WhenAll 
 ( 
 albums 
 . 
 Select 
 ( 
 album 
  
 = 
>  
 { 
  
 // Insert rows into the Albums table. 
  
 using 
  
 var 
  
 cmd 
  
 = 
  
 connection 
 . 
 CreateInsertCommand 
 ( 
 "Albums" 
 , 
  
 new 
  
 SpannerParameterCollection 
  
 { 
  
 { 
  
 "SingerId" 
 , 
  
 SpannerDbType 
 . 
 Int64 
 , 
  
 album 
 . 
 SingerId 
  
 }, 
  
 { 
  
 "AlbumId" 
 , 
  
 SpannerDbType 
 . 
 Int64 
 , 
  
 album 
 . 
 AlbumId 
  
 }, 
  
 { 
  
 "AlbumTitle" 
 , 
  
 SpannerDbType 
 . 
 String 
 , 
 album 
 . 
 AlbumTitle 
  
 } 
  
 }); 
  
 cmd 
 . 
 Transaction 
  
 = 
  
 transaction 
 ; 
  
 return 
  
 cmd 
 . 
 ExecuteNonQueryAsync 
 (); 
  
 })); 
  
 }); 
  
 Console 
 . 
 WriteLine 
 ( 
 "Data inserted." 
 ); 
  
 } 
 } 
 

Go

You write data using a Mutation . A Mutation is a container for mutation operations. A Mutation represents a sequence of inserts, updates, or deletes that can be applied atomically to different rows and tables in a Spanner database.

Use Mutation.InsertOrUpdate() to construct an INSERT_OR_UPDATE mutation, which adds a new row or updates column values if the row already exists. Alternatively, use Mutation.Insert() method to construct an INSERT mutation, which adds a new row.

Client.Apply() applies mutations atomically to a database.

This code shows how to write the data:

  import 
  
 ( 
  
 "context" 
  
 "io" 
  
 "cloud.google.com/go/spanner" 
 ) 
 func 
  
 write 
 ( 
 w 
  
 io 
 . 
 Writer 
 , 
  
 db 
  
 string 
 ) 
  
 error 
  
 { 
  
 ctx 
  
 := 
  
 context 
 . 
 Background 
 () 
  
 client 
 , 
  
 err 
  
 := 
  
 spanner 
 . 
 NewClient 
 ( 
 ctx 
 , 
  
 db 
 ) 
  
 if 
  
 err 
  
 != 
  
 nil 
  
 { 
  
 return 
  
 err 
  
 } 
  
 defer 
  
 client 
 . 
 Close 
 () 
  
 singerColumns 
  
 := 
  
 [] 
 string 
 { 
 "SingerId" 
 , 
  
 "FirstName" 
 , 
  
 "LastName" 
 } 
  
 albumColumns 
  
 := 
  
 [] 
 string 
 { 
 "SingerId" 
 , 
  
 "AlbumId" 
 , 
  
 "AlbumTitle" 
 } 
  
 m 
  
 := 
  
 [] 
 * 
 spanner 
 . 
 Mutation 
 { 
  
 spanner 
 . 
  InsertOrUpdate 
 
 ( 
 "Singers" 
 , 
  
 singerColumns 
 , 
  
 [] 
 interface 
 {}{ 
 1 
 , 
  
 "Marc" 
 , 
  
 "Richards" 
 }), 
  
 spanner 
 . 
  InsertOrUpdate 
 
 ( 
 "Singers" 
 , 
  
 singerColumns 
 , 
  
 [] 
 interface 
 {}{ 
 2 
 , 
  
 "Catalina" 
 , 
  
 "Smith" 
 }), 
  
 spanner 
 . 
  InsertOrUpdate 
 
 ( 
 "Singers" 
 , 
  
 singerColumns 
 , 
  
 [] 
 interface 
 {}{ 
 3 
 , 
  
 "Alice" 
 , 
  
 "Trentor" 
 }), 
  
 spanner 
 . 
  InsertOrUpdate 
 
 ( 
 "Singers" 
 , 
  
 singerColumns 
 , 
  
 [] 
 interface 
 {}{ 
 4 
 , 
  
 "Lea" 
 , 
  
 "Martin" 
 }), 
  
 spanner 
 . 
  InsertOrUpdate 
 
 ( 
 "Singers" 
 , 
  
 singerColumns 
 , 
  
 [] 
 interface 
 {}{ 
 5 
 , 
  
 "David" 
 , 
  
 "Lomond" 
 }), 
  
 spanner 
 . 
  InsertOrUpdate 
 
 ( 
 "Albums" 
 , 
  
 albumColumns 
 , 
  
 [] 
 interface 
 {}{ 
 1 
 , 
  
 1 
 , 
  
 "Total Junk" 
 }), 
  
 spanner 
 . 
  InsertOrUpdate 
 
 ( 
 "Albums" 
 , 
  
 albumColumns 
 , 
  
 [] 
 interface 
 {}{ 
 1 
 , 
  
 2 
 , 
  
 "Go, Go, Go" 
 }), 
  
 spanner 
 . 
  InsertOrUpdate 
 
 ( 
 "Albums" 
 , 
  
 albumColumns 
 , 
  
 [] 
 interface 
 {}{ 
 2 
 , 
  
 1 
 , 
  
 "Green" 
 }), 
  
 spanner 
 . 
  InsertOrUpdate 
 
 ( 
 "Albums" 
 , 
  
 albumColumns 
 , 
  
 [] 
 interface 
 {}{ 
 2 
 , 
  
 2 
 , 
  
 "Forever Hold Your Peace" 
 }), 
  
 spanner 
 . 
  InsertOrUpdate 
 
 ( 
 "Albums" 
 , 
  
 albumColumns 
 , 
  
 [] 
 interface 
 {}{ 
 2 
 , 
  
 3 
 , 
  
 "Terrified" 
 }), 
  
 } 
  
 _ 
 , 
  
 err 
  
 = 
  
 client 
 . 
  Apply 
 
 ( 
 ctx 
 , 
  
 m 
 ) 
  
 return 
  
 err 
 } 
 

Java

You write data using a Mutation object. A Mutation object is a container for mutation operations. A Mutation represents a sequence of inserts, updates, and deletes that Spanner applies atomically to different rows and tables in a Spanner database.

The newInsertBuilder() method in the Mutation class constructs an INSERT mutation, which inserts a new row in a table. If the row already exists, the write fails. Alternatively, you can use the newInsertOrUpdateBuilder method to construct an INSERT_OR_UPDATE mutation, which updates column values if the row already exists.

The write() method in the DatabaseClient class writes the mutations. All mutations in a single batch are applied atomically.

This code shows how to write the data:

  static 
  
 final 
  
 List<Singer> 
  
 SINGERS 
  
 = 
  
 Arrays 
 . 
 asList 
 ( 
  
 new 
  
 Singer 
 ( 
 1 
 , 
  
 "Marc" 
 , 
  
 "Richards" 
 ), 
  
 new 
  
 Singer 
 ( 
 2 
 , 
  
 "Catalina" 
 , 
  
 "Smith" 
 ), 
  
 new 
  
 Singer 
 ( 
 3 
 , 
  
 "Alice" 
 , 
  
 "Trentor" 
 ), 
  
 new 
  
 Singer 
 ( 
 4 
 , 
  
 "Lea" 
 , 
  
 "Martin" 
 ), 
  
 new 
  
 Singer 
 ( 
 5 
 , 
  
 "David" 
 , 
  
 "Lomond" 
 )); 
 static 
  
 final 
  
 List<Album> 
  
 ALBUMS 
  
 = 
  
 Arrays 
 . 
 asList 
 ( 
  
 new 
  
 Album 
 ( 
 1 
 , 
  
 1 
 , 
  
 "Total Junk" 
 ), 
  
 new 
  
 Album 
 ( 
 1 
 , 
  
 2 
 , 
  
 "Go, Go, Go" 
 ), 
  
 new 
  
 Album 
 ( 
 2 
 , 
  
 1 
 , 
  
 "Green" 
 ), 
  
 new 
  
 Album 
 ( 
 2 
 , 
  
 2 
 , 
  
 "Forever Hold Your Peace" 
 ), 
  
 new 
  
 Album 
 ( 
 2 
 , 
  
 3 
 , 
  
 "Terrified" 
 )); 
 static 
  
 void 
  
 writeExampleData 
 ( 
 DatabaseClient 
  
 dbClient 
 ) 
  
 { 
  
 List<Mutation> 
  
 mutations 
  
 = 
  
 new 
  
 ArrayList 
<> (); 
  
 for 
  
 ( 
 Singer 
  
 singer 
  
 : 
  
 SINGERS 
 ) 
  
 { 
  
 mutations 
 . 
 add 
 ( 
  
 Mutation 
 . 
 newInsertBuilder 
 ( 
 "Singers" 
 ) 
  
 . 
 set 
 ( 
 "SingerId" 
 ) 
  
 . 
 to 
 ( 
 singer 
 . 
 singerId 
 ) 
  
 . 
 set 
 ( 
 "FirstName" 
 ) 
  
 . 
 to 
 ( 
 singer 
 . 
 firstName 
 ) 
  
 . 
 set 
 ( 
 "LastName" 
 ) 
  
 . 
 to 
 ( 
 singer 
 . 
 lastName 
 ) 
  
 . 
 build 
 ()); 
  
 } 
  
 for 
  
 ( 
 Album 
  
 album 
  
 : 
  
 ALBUMS 
 ) 
  
 { 
  
 mutations 
 . 
 add 
 ( 
  
 Mutation 
 . 
 newInsertBuilder 
 ( 
 "Albums" 
 ) 
  
 . 
 set 
 ( 
 "SingerId" 
 ) 
  
 . 
 to 
 ( 
 album 
 . 
 singerId 
 ) 
  
 . 
 set 
 ( 
 "AlbumId" 
 ) 
  
 . 
 to 
 ( 
 album 
 . 
 albumId 
 ) 
  
 . 
 set 
 ( 
 "AlbumTitle" 
 ) 
  
 . 
 to 
 ( 
 album 
 . 
 albumTitle 
 ) 
  
 . 
 build 
 ()); 
  
 } 
  
 dbClient 
 . 
 write 
 ( 
 mutations 
 ); 
 } 
 

Node.js

You write data using a Table object. The Table.insert() method adds new rows to the table. All inserts in a single batch are applied atomically.

This code shows how to write the data:

  // Imports the Google Cloud client library 
 const 
  
 { 
 Spanner 
 } 
  
 = 
  
 require 
 ( 
 ' @google-cloud/spanner 
' 
 ); 
 /** 
 * TODO(developer): Uncomment the following lines before running the sample. 
 */ 
 // const projectId = 'my-project-id'; 
 // const instanceId = 'my-instance'; 
 // const databaseId = 'my-database'; 
 // Creates a client 
 const 
  
 spanner 
  
 = 
  
 new 
  
  Spanner 
 
 ({ 
  
 projectId 
 : 
  
 projectId 
 , 
 }); 
 // Gets a reference to a Cloud Spanner instance and database 
 const 
  
 instance 
  
 = 
  
 spanner 
 . 
 instance 
 ( 
 instanceId 
 ); 
 const 
  
 database 
  
 = 
  
 instance 
 . 
 database 
 ( 
 databaseId 
 ); 
 // Instantiate Spanner table objects 
 const 
  
 singersTable 
  
 = 
  
 database 
 . 
 table 
 ( 
 'Singers' 
 ); 
 const 
  
 albumsTable 
  
 = 
  
 database 
 . 
 table 
 ( 
 'Albums' 
 ); 
 // Inserts rows into the Singers table 
 // Note: Cloud Spanner interprets Node.js numbers as FLOAT64s, so 
 // they must be converted to strings before being inserted as INT64s 
 try 
  
 { 
  
 await 
  
 singersTable 
 . 
 insert 
 ([ 
  
 { 
 SingerId 
 : 
  
 '1' 
 , 
  
 FirstName 
 : 
  
 'Marc' 
 , 
  
 LastName 
 : 
  
 'Richards' 
 }, 
  
 { 
 SingerId 
 : 
  
 '2' 
 , 
  
 FirstName 
 : 
  
 'Catalina' 
 , 
  
 LastName 
 : 
  
 'Smith' 
 }, 
  
 { 
 SingerId 
 : 
  
 '3' 
 , 
  
 FirstName 
 : 
  
 'Alice' 
 , 
  
 LastName 
 : 
  
 'Trentor' 
 }, 
  
 { 
 SingerId 
 : 
  
 '4' 
 , 
  
 FirstName 
 : 
  
 'Lea' 
 , 
  
 LastName 
 : 
  
 'Martin' 
 }, 
  
 { 
 SingerId 
 : 
  
 '5' 
 , 
  
 FirstName 
 : 
  
 'David' 
 , 
  
 LastName 
 : 
  
 'Lomond' 
 }, 
  
 ]); 
  
 await 
  
 albumsTable 
 . 
 insert 
 ([ 
  
 { 
 SingerId 
 : 
  
 '1' 
 , 
  
 AlbumId 
 : 
  
 '1' 
 , 
  
 AlbumTitle 
 : 
  
 'Total Junk' 
 }, 
  
 { 
 SingerId 
 : 
  
 '1' 
 , 
  
 AlbumId 
 : 
  
 '2' 
 , 
  
 AlbumTitle 
 : 
  
 'Go, Go, Go' 
 }, 
  
 { 
 SingerId 
 : 
  
 '2' 
 , 
  
 AlbumId 
 : 
  
 '1' 
 , 
  
 AlbumTitle 
 : 
  
 'Green' 
 }, 
  
 { 
 SingerId 
 : 
  
 '2' 
 , 
  
 AlbumId 
 : 
  
 '2' 
 , 
  
 AlbumTitle 
 : 
  
 'Forever Hold your Peace' 
 }, 
  
 { 
 SingerId 
 : 
  
 '2' 
 , 
  
 AlbumId 
 : 
  
 '3' 
 , 
  
 AlbumTitle 
 : 
  
 'Terrified' 
 }, 
  
 ]); 
  
 console 
 . 
 log 
 ( 
 'Inserted data.' 
 ); 
 } 
  
 catch 
  
 ( 
 err 
 ) 
  
 { 
  
 console 
 . 
 error 
 ( 
 'ERROR:' 
 , 
  
 err 
 ); 
 } 
  
 finally 
  
 { 
  
 await 
  
 database 
 . 
 close 
 (); 
 } 
 

PHP

You write data using the Database::insertBatch method. insertBatch adds new rows to a table. All inserts in a single batch are applied atomically.

This code shows how to write the data:

  use Google\Cloud\Spanner\SpannerClient; 
 /** 
 * Inserts sample data into the given database. 
 * 
 * The database and table must already exist and can be created using 
 * `create_database`. 
 * Example: 
 * ``` 
 * insert_data($instanceId, $databaseId); 
 * ``` 
 * 
 * @param string $instanceId The Spanner instance ID. 
 * @param string $databaseId The Spanner database ID. 
 */ 
 function insert_data(string $instanceId, string $databaseId): void 
 { 
 $spanner = new SpannerClient(); 
 $instance = $spanner->instance($instanceId); 
 $database = $instance->database($databaseId); 
 $operation = $database->transaction(['singleUse' => true]) 
 ->insertBatch('Singers', [ 
 ['SingerId' => 1, 'FirstName' => 'Marc', 'LastName' => 'Richards'], 
 ['SingerId' => 2, 'FirstName' => 'Catalina', 'LastName' => 'Smith'], 
 ['SingerId' => 3, 'FirstName' => 'Alice', 'LastName' => 'Trentor'], 
 ['SingerId' => 4, 'FirstName' => 'Lea', 'LastName' => 'Martin'], 
 ['SingerId' => 5, 'FirstName' => 'David', 'LastName' => 'Lomond'], 
 ]) 
 ->insertBatch('Albums', [ 
 ['SingerId' => 1, 'AlbumId' => 1, 'AlbumTitle' => 'Total Junk'], 
 ['SingerId' => 1, 'AlbumId' => 2, 'AlbumTitle' => 'Go, Go, Go'], 
 ['SingerId' => 2, 'AlbumId' => 1, 'AlbumTitle' => 'Green'], 
 ['SingerId' => 2, 'AlbumId' => 2, 'AlbumTitle' => 'Forever Hold Your Peace'], 
 ['SingerId' => 2, 'AlbumId' => 3, 'AlbumTitle' => 'Terrified'] 
 ]) 
 ->commit(); 
 print('Inserted data.' . PHP_EOL); 
 } 
 

Python

You write data using a Batch object. A Batch object is a container for mutation operations. A mutation represents a sequence of inserts, updates, or deletes that can be applied atomically to different rows and tables in a Spanner database.

The insert() method in the Batch class is used to add one or more insert mutations to the batch. All mutations in a single batch are applied atomically.

This code shows how to write the data:

  def 
  
 insert_data 
 ( 
 instance_id 
 , 
 database_id 
 ): 
  
 """Inserts sample data into the given database. 
 The database and table must already exist and can be created using 
 `create_database`. 
 """ 
 spanner_client 
 = 
 spanner 
 . 
 Client 
 () 
 instance 
 = 
 spanner_client 
 . 
 instance 
 ( 
 instance_id 
 ) 
 database 
 = 
 instance 
 . 
 database 
 ( 
 database_id 
 ) 
 with 
 database 
 . 
 batch 
 () 
 as 
 batch 
 : 
 batch 
 . 
 insert 
 ( 
 table 
 = 
 "Singers" 
 , 
 columns 
 = 
 ( 
 "SingerId" 
 , 
 "FirstName" 
 , 
 "LastName" 
 ), 
 values 
 = 
 [ 
 ( 
 1 
 , 
 "Marc" 
 , 
 "Richards" 
 ), 
 ( 
 2 
 , 
 "Catalina" 
 , 
 "Smith" 
 ), 
 ( 
 3 
 , 
 "Alice" 
 , 
 "Trentor" 
 ), 
 ( 
 4 
 , 
 "Lea" 
 , 
 "Martin" 
 ), 
 ( 
 5 
 , 
 "David" 
 , 
 "Lomond" 
 ), 
 ], 
 ) 
 batch 
 . 
 insert 
 ( 
 table 
 = 
 "Albums" 
 , 
 columns 
 = 
 ( 
 "SingerId" 
 , 
 "AlbumId" 
 , 
 "AlbumTitle" 
 ), 
 values 
 = 
 [ 
 ( 
 1 
 , 
 1 
 , 
 "Total Junk" 
 ), 
 ( 
 1 
 , 
 2 
 , 
 "Go, Go, Go" 
 ), 
 ( 
 2 
 , 
 1 
 , 
 "Green" 
 ), 
 ( 
 2 
 , 
 2 
 , 
 "Forever Hold Your Peace" 
 ), 
 ( 
 2 
 , 
 3 
 , 
 "Terrified" 
 ), 
 ], 
 ) 
 print 
 ( 
 "Inserted data." 
 ) 
 

Ruby

You write data using a Client object. The Client#commit method creates and commits a transaction for writes that execute atomically at a single logical point in time across columns, rows, and tables in a database.

This code shows how to write the data:

  # project_id  = "Your Google Cloud project ID" 
 # instance_id = "Your Spanner instance ID" 
 # database_id = "Your Spanner database ID" 
 require 
  
 "google/cloud/spanner" 
 spanner 
  
 = 
  
 Google 
 :: 
 Cloud 
 :: 
 Spanner 
 . 
 new 
  
 project 
 : 
  
 project_id 
 client 
  
 = 
  
 spanner 
 . 
 client 
  
 instance_id 
 , 
  
 database_id 
 client 
 . 
 commit 
  
 do 
  
 | 
 c 
 | 
  
 c 
 . 
 insert 
  
 "Singers" 
 , 
  
 [ 
  
 { 
  
 SingerId 
 : 
  
 1 
 , 
  
 FirstName 
 : 
  
 "Marc" 
 , 
  
 LastName 
 : 
  
 "Richards" 
  
 }, 
  
 { 
  
 SingerId 
 : 
  
 2 
 , 
  
 FirstName 
 : 
  
 "Catalina" 
 , 
  
 LastName 
 : 
  
 "Smith" 
  
 }, 
  
 { 
  
 SingerId 
 : 
  
 3 
 , 
  
 FirstName 
 : 
  
 "Alice" 
 , 
  
 LastName 
 : 
  
 "Trentor" 
  
 }, 
  
 { 
  
 SingerId 
 : 
  
 4 
 , 
  
 FirstName 
 : 
  
 "Lea" 
 , 
  
 LastName 
 : 
  
 "Martin" 
  
 }, 
  
 { 
  
 SingerId 
 : 
  
 5 
 , 
  
 FirstName 
 : 
  
 "David" 
 , 
  
 LastName 
 : 
  
 "Lomond" 
  
 } 
  
 ] 
  
 c 
 . 
 insert 
  
 "Albums" 
 , 
  
 [ 
  
 { 
  
 SingerId 
 : 
  
 1 
 , 
  
 AlbumId 
 : 
  
 1 
 , 
  
 AlbumTitle 
 : 
  
 "Total Junk" 
  
 }, 
  
 { 
  
 SingerId 
 : 
  
 1 
 , 
  
 AlbumId 
 : 
  
 2 
 , 
  
 AlbumTitle 
 : 
  
 "Go, Go, Go" 
  
 }, 
  
 { 
  
 SingerId 
 : 
  
 2 
 , 
  
 AlbumId 
 : 
  
 1 
 , 
  
 AlbumTitle 
 : 
  
 "Green" 
  
 }, 
  
 { 
  
 SingerId 
 : 
  
 2 
 , 
  
 AlbumId 
 : 
  
 2 
 , 
  
 AlbumTitle 
 : 
  
 "Forever Hold Your Peace" 
  
 }, 
  
 { 
  
 SingerId 
 : 
  
 2 
 , 
  
 AlbumId 
 : 
  
 3 
 , 
  
 AlbumTitle 
 : 
  
 "Terrified" 
  
 } 
  
 ] 
 end 
 puts 
  
 "Inserted data" 
 

Update rows in a table

Suppose that sales of Albums(1, 1) are lower than expected. As a result, you want to move $200,000 from the marketing budget of Albums(2, 2) to Albums(1, 1) , but only if the money is available in the budget of Albums(2, 2) .

C++

Use the Transaction() function to run a transaction for a client.

Here's the code to run the transaction:

  void 
  
 ReadWriteTransaction 
 ( 
 google 
 :: 
 cloud 
 :: 
 spanner 
 :: 
 Client 
  
 client 
 ) 
  
 { 
  
 namespace 
  
 spanner 
  
 = 
  
 :: 
 google 
 :: 
 cloud 
 :: 
 spanner 
 ; 
  
 using 
  
 :: 
 google 
 :: 
 cloud 
 :: 
 StatusOr 
 ; 
  
 // A helper to read a single album MarketingBudget. 
  
 auto 
  
 get_current_budget 
  
 = 
  
 []( 
 spanner 
 :: 
 Client 
  
 client 
 , 
  
 spanner 
 :: 
 Transaction 
  
 txn 
 , 
  
 std 
 :: 
 int64_t 
  
 singer_id 
 , 
  
 std 
 :: 
 int64_t 
  
 album_id 
 ) 
  
 - 
>  
 StatusOr<std 
 :: 
 int64_t 
>  
 { 
  
 auto 
  
 key 
  
 = 
  
 spanner 
 :: 
 KeySet 
 (). 
 AddKey 
 ( 
 spanner 
 :: 
 MakeKey 
 ( 
 singer_id 
 , 
  
 album_id 
 )); 
  
 auto 
  
 rows 
  
 = 
  
 client 
 . 
 Read 
 ( 
 std 
 :: 
 move 
 ( 
 txn 
 ), 
  
 "Albums" 
 , 
  
 std 
 :: 
 move 
 ( 
 key 
 ), 
  
 { 
 "MarketingBudget" 
 }); 
  
 using 
  
 RowType 
  
 = 
  
 std 
 :: 
 tuple<std 
 :: 
 int64_t 
> ; 
  
 auto 
  
 row 
  
 = 
  
 spanner 
 :: 
 GetSingularRow 
 ( 
 spanner 
 :: 
 StreamOf<RowType> 
 ( 
 rows 
 )); 
  
 if 
  
 ( 
 ! 
 row 
 ) 
  
 return 
  
 std 
 :: 
 move 
 ( 
 row 
 ). 
 status 
 (); 
  
 return 
  
 std 
 :: 
 get<0> 
 ( 
 * 
 std 
 :: 
 move 
 ( 
 row 
 )); 
  
 }; 
  
 auto 
  
 commit 
  
 = 
  
 client 
 . 
 Commit 
 ( 
  
 [ 
& client 
 , 
  
& get_current_budget 
 ]( 
  
 spanner 
 :: 
 Transaction 
  
 const 
&  
 txn 
 ) 
  
 - 
>  
 StatusOr<spanner 
 :: 
 Mutations 
>  
 { 
  
 auto 
  
 b1 
  
 = 
  
 get_current_budget 
 ( 
 client 
 , 
  
 txn 
 , 
  
 1 
 , 
  
 1 
 ); 
  
 if 
  
 ( 
 ! 
 b1 
 ) 
  
 return 
  
 std 
 :: 
 move 
 ( 
 b1 
 ). 
 status 
 (); 
  
 auto 
  
 b2 
  
 = 
  
 get_current_budget 
 ( 
 client 
 , 
  
 txn 
 , 
  
 2 
 , 
  
 2 
 ); 
  
 if 
  
 ( 
 ! 
 b2 
 ) 
  
 return 
  
 std 
 :: 
 move 
 ( 
 b2 
 ). 
 status 
 (); 
  
 std 
 :: 
 int64_t 
  
 transfer_amount 
  
 = 
  
 200000 
 ; 
  
 return 
  
 spanner 
 :: 
 Mutations 
 { 
  
 spanner 
 :: 
 UpdateMutationBuilder 
 ( 
  
 "Albums" 
 , 
  
 { 
 "SingerId" 
 , 
  
 "AlbumId" 
 , 
  
 "MarketingBudget" 
 }) 
  
 . 
 EmplaceRow 
 ( 
 1 
 , 
  
 1 
 , 
  
 * 
 b1 
  
 + 
  
 transfer_amount 
 ) 
  
 . 
 EmplaceRow 
 ( 
 2 
 , 
  
 2 
 , 
  
 * 
 b2 
  
 - 
  
 transfer_amount 
 ) 
  
 . 
 Build 
 ()}; 
  
 }); 
  
 if 
  
 ( 
 ! 
 commit 
 ) 
  
 throw 
  
 std 
 :: 
 move 
 ( 
 commit 
 ). 
 status 
 (); 
  
 std 
 :: 
 cout 
 << 
 "Transfer was successful [spanner_read_write_transaction] 
 \n 
 " 
 ; 
 } 
 

C#

For .NET Standard 2.0 (or .NET 4.5) and newer, you can use the .NET framework's TransactionScope() to run a transaction. For all supported versions of .NET, you can create a transaction by setting the result of SpannerConnection.BeginTransactionAsync as the Transaction property of SpannerCommand .

Here are the two ways to run the transaction:

.NET Standard 2.0

  using 
  
  Google.Cloud.Spanner.Data 
 
 ; 
 using 
  
 System 
 ; 
 using 
  
 System.Threading.Tasks 
 ; 
 using 
  
 System.Transactions 
 ; 
 public 
  
 class 
  
 ReadWriteWithTransactionAsyncSample 
 { 
  
 public 
  
 async 
  
 Task<int> 
  
 ReadWriteWithTransactionAsync 
 ( 
 string 
  
 projectId 
 , 
  
 string 
  
 instanceId 
 , 
  
 string 
  
 databaseId 
 ) 
  
 { 
  
 // This sample transfers 200,000 from the MarketingBudget 
  
 // field of the second Album to the first Album. Make sure to run 
  
 // the Add Column and Write Data To New Column samples first, 
  
 // in that order. 
  
 string 
  
 connectionString 
  
 = 
  
 $"Data Source=projects/{projectId}/instances/{instanceId}/databases/{databaseId}" 
 ; 
  
 using 
  
 TransactionScope 
  
 scope 
  
 = 
  
 new 
  
 TransactionScope 
 ( 
 TransactionScopeAsyncFlowOption 
 . 
 Enabled 
 ); 
  
 decimal 
  
 transferAmount 
  
 = 
  
 200000 
 ; 
  
 decimal 
  
 secondBudget 
  
 = 
  
 0 
 ; 
  
 decimal 
  
 firstBudget 
  
 = 
  
 0 
 ; 
  
 using 
  
 var 
  
 connection 
  
 = 
  
 new 
  
  SpannerConnection 
 
 ( 
 connectionString 
 ); 
  
 using 
  
 var 
  
 cmdLookup1 
  
 = 
  
 connection 
 . 
  CreateSelectCommand 
 
 ( 
 "SELECT * FROM Albums WHERE SingerId = 2 AND AlbumId = 2" 
 ); 
  
 using 
  
 ( 
 var 
  
 reader 
  
 = 
  
 await 
  
 cmdLookup1 
 . 
  ExecuteReaderAsync 
 
 ()) 
  
 { 
  
 while 
  
 ( 
 await 
  
 reader 
 . 
  ReadAsync 
 
 ()) 
  
 { 
  
 // Read the second album's budget. 
  
 secondBudget 
  
 = 
  
 reader 
 . 
 GetFieldValue<decimal> 
 ( 
 "MarketingBudget" 
 ); 
  
 // Confirm second Album's budget is sufficient and 
  
 // if not raise an exception. Raising an exception 
  
 // will automatically roll back the transaction. 
  
 if 
  
 ( 
 secondBudget 
 < 
 transferAmount 
 ) 
  
 { 
  
 throw 
  
 new 
  
 Exception 
 ( 
 $"The second album's budget {secondBudget} is less than the amount to transfer." 
 ); 
  
 } 
  
 } 
  
 } 
  
 // Read the first album's budget. 
  
 using 
  
 var 
  
 cmdLookup2 
  
 = 
  
 connection 
 . 
  CreateSelectCommand 
 
 ( 
 "SELECT * FROM Albums WHERE SingerId = 1 and AlbumId = 1" 
 ); 
  
 using 
  
 ( 
 var 
  
 reader 
  
 = 
  
 await 
  
 cmdLookup2 
 . 
  ExecuteReaderAsync 
 
 ()) 
  
 { 
  
 while 
  
 ( 
 await 
  
 reader 
 . 
  ReadAsync 
 
 ()) 
  
 { 
  
 firstBudget 
  
 = 
  
 reader 
 . 
 GetFieldValue<decimal> 
 ( 
 "MarketingBudget" 
 ); 
  
 } 
  
 } 
  
 // Specify update command parameters. 
  
 using 
  
 var 
  
 cmdUpdate 
  
 = 
  
 connection 
 . 
  CreateUpdateCommand 
 
 ( 
 "Albums" 
 , 
  
 new 
  
  SpannerParameterCollection 
 
  
 { 
  
 { 
  
 "SingerId" 
 , 
  
  SpannerDbType 
 
 . 
  Int64 
 
  
 }, 
  
 { 
  
 "AlbumId" 
 , 
  
  SpannerDbType 
 
 . 
  Int64 
 
  
 }, 
  
 { 
  
 "MarketingBudget" 
 , 
  
  SpannerDbType 
 
 . 
  Int64 
 
  
 }, 
  
 }); 
  
 // Update second album to remove the transfer amount. 
  
 secondBudget 
  
 -= 
  
 transferAmount 
 ; 
  
 cmdUpdate 
 . 
  Parameters 
 
 [ 
 "SingerId" 
 ]. 
 Value 
  
 = 
  
 2 
 ; 
  
 cmdUpdate 
 . 
  Parameters 
 
 [ 
 "AlbumId" 
 ]. 
 Value 
  
 = 
  
 2 
 ; 
  
 cmdUpdate 
 . 
  Parameters 
 
 [ 
 "MarketingBudget" 
 ]. 
 Value 
  
 = 
  
 secondBudget 
 ; 
  
 var 
  
 rowCount 
  
 = 
  
 await 
  
 cmdUpdate 
 . 
 ExecuteNonQueryAsync 
 (); 
  
 // Update first album to add the transfer amount. 
  
 firstBudget 
  
 += 
  
 transferAmount 
 ; 
  
 cmdUpdate 
 . 
  Parameters 
 
 [ 
 "SingerId" 
 ]. 
 Value 
  
 = 
  
 1 
 ; 
  
 cmdUpdate 
 . 
  Parameters 
 
 [ 
 "AlbumId" 
 ]. 
 Value 
  
 = 
  
 1 
 ; 
  
 cmdUpdate 
 . 
  Parameters 
 
 [ 
 "MarketingBudget" 
 ]. 
 Value 
  
 = 
  
 firstBudget 
 ; 
  
 rowCount 
  
 += 
  
 await 
  
 cmdUpdate 
 . 
 ExecuteNonQueryAsync 
 (); 
  
 scope 
 . 
 Complete 
 (); 
  
 Console 
 . 
 WriteLine 
 ( 
 "Transaction complete." 
 ); 
  
 return 
  
 rowCount 
 ; 
  
 } 
 } 
 

.NET Standard 1.5

  using 
  
  Google.Cloud.Spanner.Data 
 
 ; 
 using 
  
 System 
 ; 
 using 
  
 System.Threading.Tasks 
 ; 
 public 
  
 class 
  
 ReadWriteWithTransactionCoreAsyncSample 
 { 
  
 public 
  
 async 
  
 Task<int> 
  
 ReadWriteWithTransactionCoreAsync 
 ( 
 string 
  
 projectId 
 , 
  
 string 
  
 instanceId 
 , 
  
 string 
  
 databaseId 
 ) 
  
 { 
  
 // This sample transfers 200,000 from the MarketingBudget 
  
 // field of the second Album to the first Album. Make sure to run 
  
 // the Add Column and Write Data To New Column samples first, 
  
 // in that order. 
  
 string 
  
 connectionString 
  
 = 
  
 $"Data Source=projects/{projectId}/instances/{instanceId}/databases/{databaseId}" 
 ; 
  
 decimal 
  
 transferAmount 
  
 = 
  
 200000 
 ; 
  
 decimal 
  
 secondBudget 
  
 = 
  
 0 
 ; 
  
 decimal 
  
 firstBudget 
  
 = 
  
 0 
 ; 
  
 using 
  
 var 
  
 connection 
  
 = 
  
 new 
  
  SpannerConnection 
 
 ( 
 connectionString 
 ); 
  
 await 
  
 connection 
 . 
  OpenAsync 
 
 (); 
  
 using 
  
 var 
  
 transaction 
  
 = 
  
 await 
  
 connection 
 . 
  BeginTransactionAsync 
 
 (); 
  
 using 
  
 var 
  
 cmdLookup1 
  
 = 
  
 connection 
 . 
  CreateSelectCommand 
 
 ( 
 "SELECT * FROM Albums WHERE SingerId = 2 AND AlbumId = 2" 
 ); 
  
 cmdLookup1 
 . 
  Transaction 
 
  
 = 
  
 transaction 
 ; 
  
 using 
  
 ( 
 var 
  
 reader 
  
 = 
  
 await 
  
 cmdLookup1 
 . 
  ExecuteReaderAsync 
 
 ()) 
  
 { 
  
 while 
  
 ( 
 await 
  
 reader 
 . 
  ReadAsync 
 
 ()) 
  
 { 
  
 // Read the second album's budget. 
  
 secondBudget 
  
 = 
  
 reader 
 . 
 GetFieldValue<decimal> 
 ( 
 "MarketingBudget" 
 ); 
  
 // Confirm second Album's budget is sufficient and 
  
 // if not raise an exception. Raising an exception 
  
 // will automatically roll back the transaction. 
  
 if 
  
 ( 
 secondBudget 
 < 
 transferAmount 
 ) 
  
 { 
  
 throw 
  
 new 
  
 Exception 
 ( 
 $"The second album's budget {secondBudget} contains less than the amount to transfer." 
 ); 
  
 } 
  
 } 
  
 } 
  
 // Read the first album's budget. 
  
 using 
  
 var 
  
 cmdLookup2 
  
 = 
  
 connection 
 . 
  CreateSelectCommand 
 
 ( 
 "SELECT * FROM Albums WHERE SingerId = 1 and AlbumId = 1" 
 ); 
  
 cmdLookup2 
 . 
  Transaction 
 
  
 = 
  
 transaction 
 ; 
  
 using 
  
 ( 
 var 
  
 reader 
  
 = 
  
 await 
  
 cmdLookup2 
 . 
  ExecuteReaderAsync 
 
 ()) 
  
 { 
  
 while 
  
 ( 
 await 
  
 reader 
 . 
  ReadAsync 
 
 ()) 
  
 { 
  
 firstBudget 
  
 = 
  
 reader 
 . 
 GetFieldValue<decimal> 
 ( 
 "MarketingBudget" 
 ); 
  
 } 
  
 } 
  
 // Specify update command parameters. 
  
 using 
  
 var 
  
 cmdUpdate 
  
 = 
  
 connection 
 . 
  CreateUpdateCommand 
 
 ( 
 "Albums" 
 , 
  
 new 
  
  SpannerParameterCollection 
 
  
 { 
  
 { 
  
 "SingerId" 
 , 
  
  SpannerDbType 
 
 . 
  Int64 
 
  
 }, 
  
 { 
  
 "AlbumId" 
 , 
  
  SpannerDbType 
 
 . 
  Int64 
 
  
 }, 
  
 { 
  
 "MarketingBudget" 
 , 
  
  SpannerDbType 
 
 . 
  Int64 
 
  
 }, 
  
 }); 
  
 cmdUpdate 
 . 
  Transaction 
 
  
 = 
  
 transaction 
 ; 
  
 // Update second album to remove the transfer amount. 
  
 secondBudget 
  
 -= 
  
 transferAmount 
 ; 
  
 cmdUpdate 
 . 
  Parameters 
 
 [ 
 "SingerId" 
 ]. 
 Value 
  
 = 
  
 2 
 ; 
  
 cmdUpdate 
 . 
  Parameters 
 
 [ 
 "AlbumId" 
 ]. 
 Value 
  
 = 
  
 2 
 ; 
  
 cmdUpdate 
 . 
  Parameters 
 
 [ 
 "MarketingBudget" 
 ]. 
 Value 
  
 = 
  
 secondBudget 
 ; 
  
 var 
  
 rowCount 
  
 = 
  
 await 
  
 cmdUpdate 
 . 
 ExecuteNonQueryAsync 
 (); 
  
 // Update first album to add the transfer amount. 
  
 firstBudget 
  
 += 
  
 transferAmount 
 ; 
  
 cmdUpdate 
 . 
  Parameters 
 
 [ 
 "SingerId" 
 ]. 
 Value 
  
 = 
  
 1 
 ; 
  
 cmdUpdate 
 . 
  Parameters 
 
 [ 
 "AlbumId" 
 ]. 
 Value 
  
 = 
  
 1 
 ; 
  
 cmdUpdate 
 . 
  Parameters 
 
 [ 
 "MarketingBudget" 
 ]. 
 Value 
  
 = 
  
 firstBudget 
 ; 
  
 rowCount 
  
 += 
  
 await 
  
 cmdUpdate 
 . 
 ExecuteNonQueryAsync 
 (); 
  
 await 
  
 transaction 
 . 
 CommitAsync 
 (); 
  
 Console 
 . 
 WriteLine 
 ( 
 "Transaction complete." 
 ); 
  
 return 
  
 rowCount 
 ; 
  
 } 
 } 
 

Go

Use the ReadWriteTransaction type for executing a body of work in the context of a read-write transaction. Client.ReadWriteTransaction() returns a ReadWriteTransaction object.

The sample uses ReadWriteTransaction.ReadRow() to retrieve a row of data.

The sample also uses ReadWriteTransaction.BufferWrite() , which adds a list of mutations to the set of updates that will be applied when the transaction is committed.

The sample also uses the Key type, which represents a row key in a Spanner table or index.

  import 
  
 ( 
  
 "context" 
  
 "fmt" 
  
 "io" 
  
 "cloud.google.com/go/spanner" 
 ) 
 func 
  
 writeWithTransaction 
 ( 
 w 
  
 io 
 . 
 Writer 
 , 
  
 db 
  
 string 
 ) 
  
 error 
  
 { 
  
 ctx 
  
 := 
  
 context 
 . 
 Background 
 () 
  
 client 
 , 
  
 err 
  
 := 
  
 spanner 
 . 
 NewClient 
 ( 
 ctx 
 , 
  
 db 
 ) 
  
 if 
  
 err 
  
 != 
  
 nil 
  
 { 
  
 return 
  
 err 
  
 } 
  
 defer 
  
 client 
 . 
 Close 
 () 
  
 _ 
 , 
  
 err 
  
 = 
  
 client 
 . 
 ReadWriteTransaction 
 ( 
 ctx 
 , 
  
 func 
 ( 
 ctx 
  
 context 
 . 
 Context 
 , 
  
 txn 
  
 * 
 spanner 
 . 
 ReadWriteTransaction 
 ) 
  
 error 
  
 { 
  
 getBudget 
  
 := 
  
 func 
 ( 
 key 
  
 spanner 
 . 
  Key 
 
 ) 
  
 ( 
 int64 
 , 
  
 error 
 ) 
  
 { 
  
 row 
 , 
  
 err 
  
 := 
  
 txn 
 . 
 ReadRow 
 ( 
 ctx 
 , 
  
 "Albums" 
 , 
  
 key 
 , 
  
 [] 
 string 
 { 
 "MarketingBudget" 
 }) 
  
 if 
  
 err 
  
 != 
  
 nil 
  
 { 
  
 return 
  
 0 
 , 
  
 err 
  
 } 
  
 var 
  
 budget 
  
 int64 
  
 if 
  
 err 
  
 := 
  
 row 
 . 
  Column 
 
 ( 
 0 
 , 
  
& budget 
 ); 
  
 err 
  
 != 
  
 nil 
  
 { 
  
 return 
  
 0 
 , 
  
 err 
  
 } 
  
 return 
  
 budget 
 , 
  
 nil 
  
 } 
  
 album2Budget 
 , 
  
 err 
  
 := 
  
 getBudget 
 ( 
 spanner 
 . 
  Key 
 
 { 
 2 
 , 
  
 2 
 }) 
  
 if 
  
 err 
  
 != 
  
 nil 
  
 { 
  
 return 
  
 err 
  
 } 
  
 const 
  
 transferAmt 
  
 = 
  
 200000 
  
 if 
  
 album2Budget 
  
> = 
  
 transferAmt 
  
 { 
  
 album1Budget 
 , 
  
 err 
  
 := 
  
 getBudget 
 ( 
 spanner 
 . 
 Key 
 { 
 1 
 , 
  
 1 
 }) 
  
 if 
  
 err 
  
 != 
  
 nil 
  
 { 
  
 return 
  
 err 
  
 } 
  
 album1Budget 
  
 += 
  
 transferAmt 
  
 album2Budget 
  
 -= 
  
 transferAmt 
  
 cols 
  
 := 
  
 [] 
 string 
 { 
 "SingerId" 
 , 
  
 "AlbumId" 
 , 
  
 "MarketingBudget" 
 } 
  
 txn 
 . 
 BufferWrite 
 ([] 
 * 
 spanner 
 . 
 Mutation 
 { 
  
 spanner 
 . 
 Update 
 ( 
 "Albums" 
 , 
  
 cols 
 , 
  
 [] 
 interface 
 {}{ 
 1 
 , 
  
 1 
 , 
  
 album1Budget 
 }), 
  
 spanner 
 . 
 Update 
 ( 
 "Albums" 
 , 
  
 cols 
 , 
  
 [] 
 interface 
 {}{ 
 2 
 , 
  
 2 
 , 
  
 album2Budget 
 }), 
  
 }) 
  
 fmt 
 . 
 Fprintf 
 ( 
 w 
 , 
  
 "Moved %d from Album2's MarketingBudget to Album1's." 
 , 
  
 transferAmt 
 ) 
  
 } 
  
 return 
  
 nil 
  
 }) 
  
 return 
  
 err 
 } 
 

Java

Use the TransactionRunner interface for executing a body of work in the context of a read-write transaction. This interface contains the method run() , which is used to execute a read- write transaction, with retries as necessary. The readWriteTransaction method of the DatabaseClient class returns a TransactionRunner object for executing a single logical transaction.

The TransactionRunner.TransactionCallable class contains a run() method for performing a single attempt of a transaction. run() takes a TransactionContext object, which is a context for a transaction.

The sample uses the Struct class, which is handy for storing the results of the readRow() calls. The sample also uses the Key class, which represents a row key in a Spanner table or index.

Here's the code to run the transaction:

  static 
  
 void 
  
 writeWithTransaction 
 ( 
 DatabaseClient 
  
 dbClient 
 ) 
  
 { 
  
 dbClient 
  
 . 
 readWriteTransaction 
 () 
  
 . 
 run 
 ( 
 transaction 
  
 - 
>  
 { 
  
 // Transfer marketing budget from one album to another. We do it in a transaction to 
  
 // ensure that the transfer is atomic. 
  
 Struct 
  
 row 
  
 = 
  
 transaction 
 . 
 readRow 
 ( 
 "Albums" 
 , 
  
 Key 
 . 
 of 
 ( 
 2 
 , 
  
 2 
 ), 
  
 Arrays 
 . 
 asList 
 ( 
 "MarketingBudget" 
 )); 
  
 long 
  
 album2Budget 
  
 = 
  
 row 
 . 
 getLong 
 ( 
 0 
 ); 
  
 // Transaction will only be committed if this condition still holds at the time of 
  
 // commit. Otherwise it will be aborted and the callable will be rerun by the 
  
 // client library. 
  
 long 
  
 transfer 
  
 = 
  
 200000 
 ; 
  
 if 
  
 ( 
 album2Budget 
  
> = 
  
 transfer 
 ) 
  
 { 
  
 long 
  
 album1Budget 
  
 = 
  
 transaction 
  
 . 
 readRow 
 ( 
 "Albums" 
 , 
  
 Key 
 . 
 of 
 ( 
 1 
 , 
  
 1 
 ), 
  
 Arrays 
 . 
 asList 
 ( 
 "MarketingBudget" 
 )) 
  
 . 
 getLong 
 ( 
 0 
 ); 
  
 album1Budget 
  
 += 
  
 transfer 
 ; 
  
 album2Budget 
  
 -= 
  
 transfer 
 ; 
  
 transaction 
 . 
 buffer 
 ( 
  
 Mutation 
 . 
 newUpdateBuilder 
 ( 
 "Albums" 
 ) 
  
 . 
 set 
 ( 
 "SingerId" 
 ) 
  
 . 
 to 
 ( 
 1 
 ) 
  
 . 
 set 
 ( 
 "AlbumId" 
 ) 
  
 . 
 to 
 ( 
 1 
 ) 
  
 . 
 set 
 ( 
 "MarketingBudget" 
 ) 
  
 . 
 to 
 ( 
 album1Budget 
 ) 
  
 . 
 build 
 ()); 
  
 transaction 
 . 
 buffer 
 ( 
  
 Mutation 
 . 
 newUpdateBuilder 
 ( 
 "Albums" 
 ) 
  
 . 
 set 
 ( 
 "SingerId" 
 ) 
  
 . 
 to 
 ( 
 2 
 ) 
  
 . 
 set 
 ( 
 "AlbumId" 
 ) 
  
 . 
 to 
 ( 
 2 
 ) 
  
 . 
 set 
 ( 
 "MarketingBudget" 
 ) 
  
 . 
 to 
 ( 
 album2Budget 
 ) 
  
 . 
 build 
 ()); 
  
 } 
  
 return 
  
 null 
 ; 
  
 }); 
 } 
 

Node.js

Use Database.runTransaction() to run a transaction.

Here's the code to run the transaction:

  // This sample transfers 200,000 from the MarketingBudget field 
 // of the second Album to the first Album, as long as the second 
 // Album has enough money in its budget. Make sure to run the 
 // addColumn and updateData samples first (in that order). 
 // Imports the Google Cloud client library 
 const 
  
 { 
 Spanner 
 } 
  
 = 
  
 require 
 ( 
 ' @google-cloud/spanner 
' 
 ); 
 /** 
 * TODO(developer): Uncomment the following lines before running the sample. 
 */ 
 // const projectId = 'my-project-id'; 
 // const instanceId = 'my-instance'; 
 // const databaseId = 'my-database'; 
 // Creates a client 
 const 
  
 spanner 
  
 = 
  
 new 
  
  Spanner 
 
 ({ 
  
 projectId 
 : 
  
 projectId 
 , 
 }); 
 // Gets a reference to a Cloud Spanner instance and database 
 const 
  
 instance 
  
 = 
  
 spanner 
 . 
 instance 
 ( 
 instanceId 
 ); 
 const 
  
 database 
  
 = 
  
 instance 
 . 
 database 
 ( 
 databaseId 
 ); 
 const 
  
 transferAmount 
  
 = 
  
 200000 
 ; 
 // Note: the `runTransaction()` method is non blocking and returns "void". 
 // For sequential execution of the transaction use `runTransactionAsync()` method which returns a promise. 
 // For example: await database.runTransactionAsync(async (err, transaction) => { ... }) 
 database 
 . 
  runTransaction 
 
 ( 
 async 
  
 ( 
 err 
 , 
  
 transaction 
 ) 
  
 = 
>  
 { 
  
 if 
  
 ( 
 err 
 ) 
  
 { 
  
 console 
 . 
 error 
 ( 
 err 
 ); 
  
 return 
 ; 
  
 } 
  
 let 
  
 firstBudget 
 , 
  
 secondBudget 
 ; 
  
 const 
  
 queryOne 
  
 = 
  
 { 
  
 columns 
 : 
  
 [ 
 'MarketingBudget' 
 ], 
  
 keys 
 : 
  
 [[ 
 2 
 , 
  
 2 
 ]], 
  
 // SingerId: 2, AlbumId: 2 
  
 }; 
  
 const 
  
 queryTwo 
  
 = 
  
 { 
  
 columns 
 : 
  
 [ 
 'MarketingBudget' 
 ], 
  
 keys 
 : 
  
 [[ 
 1 
 , 
  
 1 
 ]], 
  
 // SingerId: 1, AlbumId: 1 
  
 }; 
  
 Promise 
 . 
 all 
 ([ 
  
 // Reads the second album's budget 
  
 transaction 
 . 
 read 
 ( 
 'Albums' 
 , 
  
 queryOne 
 ). 
 then 
 ( 
 results 
  
 = 
>  
 { 
  
 // Gets second album's budget 
  
 const 
  
 rows 
  
 = 
  
 results 
 [ 
 0 
 ]. 
 map 
 ( 
 row 
  
 = 
>  
 row 
 . 
 toJSON 
 ()); 
  
 secondBudget 
  
 = 
  
 rows 
 [ 
 0 
 ]. 
 MarketingBudget 
 ; 
  
 console 
 . 
 log 
 ( 
 `The second album's marketing budget: 
 ${ 
 secondBudget 
 } 
 ` 
 ); 
  
 // Makes sure the second album's budget is large enough 
  
 if 
  
 ( 
 secondBudget 
 < 
 transferAmount 
 ) 
  
 { 
  
 throw 
  
 new 
  
 Error 
 ( 
  
 `The second album's budget ( 
 ${ 
 secondBudget 
 } 
 ) is less than the transfer amount ( 
 ${ 
 transferAmount 
 } 
 ).` 
 , 
  
 ); 
  
 } 
  
 }), 
  
 // Reads the first album's budget 
  
 transaction 
 . 
 read 
 ( 
 'Albums' 
 , 
  
 queryTwo 
 ). 
 then 
 ( 
 results 
  
 = 
>  
 { 
  
 // Gets first album's budget 
  
 const 
  
 rows 
  
 = 
  
 results 
 [ 
 0 
 ]. 
 map 
 ( 
 row 
  
 = 
>  
 row 
 . 
 toJSON 
 ()); 
  
 firstBudget 
  
 = 
  
 rows 
 [ 
 0 
 ]. 
 MarketingBudget 
 ; 
  
 console 
 . 
 log 
 ( 
 `The first album's marketing budget: 
 ${ 
 firstBudget 
 } 
 ` 
 ); 
  
 }), 
  
 ]) 
  
 . 
 then 
 (() 
  
 = 
>  
 { 
  
 console 
 . 
 log 
 ( 
 firstBudget 
 , 
  
 secondBudget 
 ); 
  
 // Transfers the budgets between the albums 
  
 firstBudget 
  
 += 
  
 transferAmount 
 ; 
  
 secondBudget 
  
 -= 
  
 transferAmount 
 ; 
  
 console 
 . 
 log 
 ( 
 firstBudget 
 , 
  
 secondBudget 
 ); 
  
 // Updates the database 
  
 // Note: Cloud Spanner interprets Node.js numbers as FLOAT64s, so they 
  
 // must be converted (back) to strings before being inserted as INT64s. 
  
 transaction 
 . 
 update 
 ( 
 'Albums' 
 , 
  
 [ 
  
 { 
  
 SingerId 
 : 
  
 '1' 
 , 
  
 AlbumId 
 : 
  
 '1' 
 , 
  
 MarketingBudget 
 : 
  
 firstBudget 
 . 
 toString 
 (), 
  
 }, 
  
 { 
  
 SingerId 
 : 
  
 '2' 
 , 
  
 AlbumId 
 : 
  
 '2' 
 , 
  
 MarketingBudget 
 : 
  
 secondBudget 
 . 
 toString 
 (), 
  
 }, 
  
 ]); 
  
 }) 
  
 . 
 then 
 (() 
  
 = 
>  
 { 
  
 // Commits the transaction and send the changes to the database 
  
 return 
  
 transaction 
 . 
 commit 
 (); 
  
 }) 
  
 . 
 then 
 (() 
  
 = 
>  
 { 
  
 console 
 . 
 log 
 ( 
  
 `Successfully executed read-write transaction to transfer 
 ${ 
 transferAmount 
 } 
 from Album 2 to Album 1.` 
 , 
  
 ); 
  
 }) 
  
 . 
 catch 
 ( 
 err 
  
 = 
>  
 { 
  
 console 
 . 
 error 
 ( 
 'ERROR:' 
 , 
  
 err 
 ); 
  
 }) 
  
 . 
 then 
 (() 
  
 = 
>  
 { 
  
 transaction 
 . 
 end 
 (); 
  
 // Closes the database when finished 
  
 return 
  
 database 
 . 
 close 
 (); 
  
 }); 
 }); 
 

PHP

Use Database::runTransaction to run a transaction.

Here's the code to run the transaction:

  use Google\Cloud\Spanner\SpannerClient; 
 use Google\Cloud\Spanner\Transaction; 
 use UnexpectedValueException; 
 /** 
 * Performs a read-write transaction to update two sample records in the 
 * database. 
 * 
 * This will transfer 200,000 from the `MarketingBudget` field for the second 
 * Album to the first Album. If the `MarketingBudget` for the second Album is 
 * too low, it will raise an exception. 
 * 
 * Before running this sample, you will need to run the `update_data` sample 
 * to populate the fields. 
 * Example: 
 * ``` 
 * read_write_transaction($instanceId, $databaseId); 
 * ``` 
 * 
 * @param string $instanceId The Spanner instance ID. 
 * @param string $databaseId The Spanner database ID. 
 */ 
 function read_write_transaction(string $instanceId, string $databaseId): void 
 { 
 $spanner = new SpannerClient(); 
 $instance = $spanner->instance($instanceId); 
 $database = $instance->database($databaseId); 
 $database->runTransaction(function (Transaction $t) use ($spanner) { 
 $transferAmount = 200000; 
 // Read the second album's budget. 
 $secondAlbumKey = [2, 2]; 
 $secondAlbumKeySet = $spanner->keySet(['keys' => [$secondAlbumKey]]); 
 $secondAlbumResult = $t->read( 
 'Albums', 
 $secondAlbumKeySet, 
 ['MarketingBudget'], 
 ['limit' => 1] 
 ); 
 $firstRow = $secondAlbumResult->rows()->current(); 
 $secondAlbumBudget = $firstRow['MarketingBudget']; 
 if ($secondAlbumBudget < $transferAmount) { 
 // Throwing an exception will automatically roll back the transaction. 
 throw new UnexpectedValueException( 
 'The second album\'s budget is lower than the transfer amount: ' . $transferAmount 
 ); 
 } 
 $firstAlbumKey = [1, 1]; 
 $firstAlbumKeySet = $spanner->keySet(['keys' => [$firstAlbumKey]]); 
 $firstAlbumResult = $t->read( 
 'Albums', 
 $firstAlbumKeySet, 
 ['MarketingBudget'], 
 ['limit' => 1] 
 ); 
 // Read the first album's budget. 
 $firstRow = $firstAlbumResult->rows()->current(); 
 $firstAlbumBudget = $firstRow['MarketingBudget']; 
 // Update the budgets. 
 $secondAlbumBudget -= $transferAmount; 
 $firstAlbumBudget += $transferAmount; 
 printf('Setting first album\'s budget to %s and the second album\'s ' . 
 'budget to %s.' . PHP_EOL, $firstAlbumBudget, $secondAlbumBudget); 
 // Update the rows. 
 $t->updateBatch('Albums', [ 
 ['SingerId' => 1, 'AlbumId' => 1, 'MarketingBudget' => $firstAlbumBudget], 
 ['SingerId' => 2, 'AlbumId' => 2, 'MarketingBudget' => $secondAlbumBudget], 
 ]); 
 // Commit the transaction! 
 $t->commit(); 
 print('Transaction complete.' . PHP_EOL); 
 }); 
 } 
 

Python

Use the run_in_transaction() method of the Database class to run a transaction.

Here's the code to run the transaction:

  def 
  
 read_write_transaction 
 ( 
 instance_id 
 , 
 database_id 
 ): 
  
 """Performs a read-write transaction to update two sample records in the 
 database. 
 This will transfer 200,000 from the `MarketingBudget` field for the second 
 Album to the first Album. If the `MarketingBudget` is too low, it will 
 raise an exception. 
 Before running this sample, you will need to run the `update_data` sample 
 to populate the fields. 
 """ 
 spanner_client 
 = 
 spanner 
 . 
 Client 
 () 
 instance 
 = 
 spanner_client 
 . 
 instance 
 ( 
 instance_id 
 ) 
 database 
 = 
 instance 
 . 
 database 
 ( 
 database_id 
 ) 
 def 
  
 update_albums 
 ( 
 transaction 
 ): 
 # Read the second album budget. 
 second_album_keyset 
 = 
 spanner 
 . 
 KeySet 
 ( 
 keys 
 = 
 [( 
 2 
 , 
 2 
 )]) 
 second_album_result 
 = 
 transaction 
 . 
 read 
 ( 
 table 
 = 
 "Albums" 
 , 
 columns 
 = 
 ( 
 "MarketingBudget" 
 ,), 
 keyset 
 = 
 second_album_keyset 
 , 
 limit 
 = 
 1 
 , 
 ) 
 second_album_row 
 = 
 list 
 ( 
 second_album_result 
 )[ 
 0 
 ] 
 second_album_budget 
 = 
 second_album_row 
 [ 
 0 
 ] 
 transfer_amount 
 = 
 200000 
 if 
 second_album_budget 
< transfer_amount 
 : 
 # Raising an exception will automatically roll back the 
 # transaction. 
 raise 
 ValueError 
 ( 
 "The second album doesn't have enough funds to transfer" 
 ) 
 # Read the first album's budget. 
 first_album_keyset 
 = 
 spanner 
 . 
 KeySet 
 ( 
 keys 
 = 
 [( 
 1 
 , 
 1 
 )]) 
 first_album_result 
 = 
 transaction 
 . 
 read 
 ( 
 table 
 = 
 "Albums" 
 , 
 columns 
 = 
 ( 
 "MarketingBudget" 
 ,), 
 keyset 
 = 
 first_album_keyset 
 , 
 limit 
 = 
 1 
 , 
 ) 
 first_album_row 
 = 
 list 
 ( 
 first_album_result 
 )[ 
 0 
 ] 
 first_album_budget 
 = 
 first_album_row 
 [ 
 0 
 ] 
 # Update the budgets. 
 second_album_budget 
 -= 
 transfer_amount 
 first_album_budget 
 += 
 transfer_amount 
 print 
 ( 
 "Setting first album's budget to 
 {} 
 and the second album's " 
 "budget to 
 {} 
 ." 
 . 
 format 
 ( 
 first_album_budget 
 , 
 second_album_budget 
 ) 
 ) 
 # Update the rows. 
 transaction 
 . 
 update 
 ( 
 table 
 = 
 "Albums" 
 , 
 columns 
 = 
 ( 
 "SingerId" 
 , 
 "AlbumId" 
 , 
 "MarketingBudget" 
 ), 
 values 
 = 
 [( 
 1 
 , 
 1 
 , 
 first_album_budget 
 ), 
 ( 
 2 
 , 
 2 
 , 
 second_album_budget 
 )], 
 ) 
 database 
 . 
 run_in_transaction 
 ( 
 update_albums 
 ) 
 print 
 ( 
 "Transaction complete." 
 ) 
 

Ruby

Use the transaction method of the Client class to run a transaction.

Here's the code to run the transaction:

  # project_id  = "Your Google Cloud project ID" 
 # instance_id = "Your Spanner instance ID" 
 # database_id = "Your Spanner database ID" 
 require 
  
 "google/cloud/spanner" 
 spanner 
  
 = 
  
 Google 
 :: 
 Cloud 
 :: 
 Spanner 
 . 
 new 
  
 project 
 : 
  
 project_id 
 client 
  
 = 
  
 spanner 
 . 
 client 
  
 instance_id 
 , 
  
 database_id 
 transfer_amount 
  
 = 
  
 200_000 
 client 
 . 
 transaction 
  
 do 
  
 | 
 transaction 
 | 
  
 first_album 
  
 = 
  
 transaction 
 . 
 read 
 ( 
 "Albums" 
 , 
  
 [ 
 :MarketingBudget 
 ] 
 , 
  
 keys 
 : 
  
 [[ 
 1 
 , 
  
 1 
 ]] 
 ) 
 . 
 rows 
 . 
 first 
  
 second_album 
  
 = 
  
 transaction 
 . 
 read 
 ( 
 "Albums" 
 , 
  
 [ 
 :MarketingBudget 
 ] 
 , 
  
 keys 
 : 
  
 [[ 
 2 
 , 
  
 2 
 ]] 
 ) 
 . 
 rows 
 . 
 first 
  
 raise 
  
 "The second album does not have enough funds to transfer" 
  
 if 
  
 second_album 
 [ 
 :MarketingBudget 
 ] 
 < 
 transfer_amount 
  
 new_first_album_budget 
  
 = 
  
 first_album 
 [ 
 :MarketingBudget 
 ] 
  
 + 
  
 transfer_amount 
  
 new_second_album_budget 
  
 = 
  
 second_album 
 [ 
 :MarketingBudget 
 ] 
  
 - 
  
 transfer_amount 
  
 transaction 
 . 
 update 
  
 "Albums" 
 , 
  
 [ 
  
 { 
  
 SingerId 
 : 
  
 1 
 , 
  
 AlbumId 
 : 
  
 1 
 , 
  
 MarketingBudget 
 : 
  
 new_first_album_budget 
  
 }, 
  
 { 
  
 SingerId 
 : 
  
 2 
 , 
  
 AlbumId 
 : 
  
 2 
 , 
  
 MarketingBudget 
 : 
  
 new_second_album_budget 
  
 } 
  
 ] 
 end 
 puts 
  
 "Transaction complete" 
 

Delete rows in a table

Each client library provides multiple ways to delete rows:

  • Delete all the rows in a table.
  • Delete a single row by specifying the key column values for the row.
  • Delete a group of rows by creating a key range.
  • Delete rows in an interleaved table by deleting the parent rows, if the interleaved table includes ON DELETE CASCADE in its schema definition.

C++

Delete rows using the DeleteMutationBuilder() function for a client.

This code shows how to delete the data:

  void 
  
 DeleteData 
 ( 
 google 
 :: 
 cloud 
 :: 
 spanner 
 :: 
 Client 
  
 client 
 ) 
  
 { 
  
 namespace 
  
 spanner 
  
 = 
  
 :: 
 google 
 :: 
 cloud 
 :: 
 spanner 
 ; 
  
 // Delete the albums with key (2,1) and (2,3). 
  
 auto 
  
 delete_albums 
  
 = 
  
 spanner 
 :: 
 DeleteMutationBuilder 
 ( 
  
 "Albums" 
 , 
  
 spanner 
 :: 
 KeySet 
 () 
  
 . 
 AddKey 
 ( 
 spanner 
 :: 
 MakeKey 
 ( 
 2 
 , 
  
 1 
 )) 
  
 . 
 AddKey 
 ( 
 spanner 
 :: 
 MakeKey 
 ( 
 2 
 , 
  
 3 
 ))) 
  
 . 
 Build 
 (); 
  
 // Delete some singers using the keys in the range [3, 5] 
  
 auto 
  
 delete_singers_range 
  
 = 
  
 spanner 
 :: 
 DeleteMutationBuilder 
 ( 
  
 "Singers" 
 , 
  
 spanner 
 :: 
 KeySet 
 (). 
 AddRange 
 ( 
 spanner 
 :: 
 MakeKeyBoundClosed 
 ( 
 3 
 ), 
  
 spanner 
 :: 
 MakeKeyBoundOpen 
 ( 
 5 
 ))) 
  
 . 
 Build 
 (); 
  
 // Deletes remaining rows from the Singers table and the Albums table, because 
  
 // the Albums table is defined with ON DELETE CASCADE. 
  
 auto 
  
 delete_singers_all 
  
 = 
  
 spanner 
 :: 
 MakeDeleteMutation 
 ( 
 "Singers" 
 , 
  
 spanner 
 :: 
 KeySet 
 :: 
 All 
 ()); 
  
 auto 
  
 commit_result 
  
 = 
  
 client 
 . 
 Commit 
 ( 
 spanner 
 :: 
 Mutations 
 { 
  
 delete_albums 
 , 
  
 delete_singers_range 
 , 
  
 delete_singers_all 
 }); 
  
 if 
  
 ( 
 ! 
 commit_result 
 ) 
  
 throw 
  
 std 
 :: 
 move 
 ( 
 commit_result 
 ). 
 status 
 (); 
  
 std 
 :: 
 cout 
 << 
 "Delete was successful [spanner_delete_data] 
 \n 
 " 
 ; 
 } 
 

C#

Delete rows using the connection.CreateDeleteCommand() method, which creates a new SpannerCommand to delete rows. The SpannerCommand.ExecuteNonQueryAsync() method deletes the rows from the table.

This example deletes the rows in the Singers table individually. The rows in the Albums table are deleted because the Albums table is interleaved in the Singers table and is defined with ON DELETE CASCADE .

  using 
  
  Google.Cloud.Spanner.Data 
 
 ; 
 using 
  
 System 
 ; 
 using 
  
 System.Collections.Generic 
 ; 
 using 
  
 System.Linq 
 ; 
 using 
  
 System.Threading.Tasks 
 ; 
 public 
  
 class 
  
 DeleteDataAsyncSample 
 { 
  
 public 
  
 class 
  
 Album 
  
 { 
  
 public 
  
 int 
  
 SingerId 
  
 { 
  
 get 
 ; 
  
 set 
 ; 
  
 } 
  
 public 
  
 int 
  
 AlbumId 
  
 { 
  
 get 
 ; 
  
 set 
 ; 
  
 } 
  
 public 
  
 string 
  
 AlbumTitle 
  
 { 
  
 get 
 ; 
  
 set 
 ; 
  
 } 
  
 } 
  
 public 
  
 async 
  
 Task<int> 
  
 DeleteDataAsync 
 ( 
 string 
  
 projectId 
 , 
  
 string 
  
 instanceId 
 , 
  
 string 
  
 databaseId 
 ) 
  
 { 
  
 string 
  
 connectionString 
  
 = 
  
 $"Data Source=projects/{projectId}/instances/{instanceId}/databases/{databaseId}" 
 ; 
  
 var 
  
 albums 
  
 = 
  
 new 
  
 List<Album> 
  
 { 
  
 new 
  
 Album 
  
 { 
  
 SingerId 
  
 = 
  
 2 
 , 
  
 AlbumId 
  
 = 
  
 1 
 , 
  
 AlbumTitle 
  
 = 
  
 "Green" 
  
 }, 
  
 new 
  
 Album 
  
 { 
  
 SingerId 
  
 = 
  
 2 
 , 
  
 AlbumId 
  
 = 
  
 3 
 , 
  
 AlbumTitle 
  
 = 
  
 "Terrified" 
  
 }, 
  
 }; 
  
 int 
  
 rowCount 
  
 = 
  
 0 
 ; 
  
 using 
  
 ( 
 var 
  
 connection 
  
 = 
  
 new 
  
  SpannerConnection 
 
 ( 
 connectionString 
 )) 
  
 { 
  
 await 
  
 connection 
 . 
  OpenAsync 
 
 (); 
  
 // Delete individual rows from the Albums table. 
  
 await 
  
 Task 
 . 
 WhenAll 
 ( 
 albums 
 . 
 Select 
 ( 
 async 
  
 album 
  
 = 
>  
 { 
  
 var 
  
 cmd 
  
 = 
  
 connection 
 . 
 CreateDeleteCommand 
 ( 
 "Albums" 
 , 
  
 new 
  
 SpannerParameterCollection 
  
 { 
  
 { 
  
 "SingerId" 
 , 
  
 SpannerDbType 
 . 
 Int64 
 , 
  
 album 
 . 
 SingerId 
  
 }, 
  
 { 
  
 "AlbumId" 
 , 
  
 SpannerDbType 
 . 
 Int64 
 , 
  
 album 
 . 
 AlbumId 
  
 } 
  
 }); 
  
 rowCount 
  
 += 
  
 await 
  
 cmd 
 . 
 ExecuteNonQueryAsync 
 (); 
  
 })); 
  
 Console 
 . 
 WriteLine 
 ( 
 "Deleted individual rows in Albums." 
 ); 
  
 // Delete a range of rows from the Singers table where the column key is >=3 and <5. 
  
 var 
  
 cmd 
  
 = 
  
 connection 
 . 
  CreateDmlCommand 
 
 ( 
 "DELETE FROM Singers WHERE SingerId >= 3 AND SingerId < 5" 
 ); 
  
 rowCount 
  
 += 
  
 await 
  
 cmd 
 . 
 ExecuteNonQueryAsync 
 (); 
  
 Console 
 . 
 WriteLine 
 ( 
 $"{rowCount} row(s) deleted from Singers." 
 ); 
  
 // Delete remaining Singers rows, which will also delete the remaining 
  
 // Albums rows since it was defined with ON DELETE CASCADE. 
  
 cmd 
  
 = 
  
 connection 
 . 
  CreateDmlCommand 
 
 ( 
 "DELETE FROM Singers WHERE true" 
 ); 
  
 rowCount 
  
 += 
  
 await 
  
 cmd 
 . 
 ExecuteNonQueryAsync 
 (); 
  
 Console 
 . 
 WriteLine 
 ( 
 $"{rowCount} row(s) deleted from Singers." 
 ); 
  
 } 
  
 return 
  
 rowCount 
 ; 
  
 } 
 } 
 

Go

Delete rows using a Mutation . Use the Mutation.Delete() method to construct a DELETE mutation, which deletes a row. The Client.Apply() method applies mutations atomically to the database.

This example deletes the rows in the Albums table individually, and then deletes all the rows in the Singers table using a KeyRange .

  import 
  
 ( 
  
 "context" 
  
 "io" 
  
 "cloud.google.com/go/spanner" 
 ) 
 func 
  
 delete 
 ( 
 w 
  
 io 
 . 
 Writer 
 , 
  
 db 
  
 string 
 ) 
  
 error 
  
 { 
  
 ctx 
  
 := 
  
 context 
 . 
 Background 
 () 
  
 client 
 , 
  
 err 
  
 := 
  
 spanner 
 . 
 NewClient 
 ( 
 ctx 
 , 
  
 db 
 ) 
  
 if 
  
 err 
  
 != 
  
 nil 
  
 { 
  
 return 
  
 err 
  
 } 
  
 defer 
  
 client 
 . 
 Close 
 () 
  
 m 
  
 := 
  
 [] 
 * 
 spanner 
 . 
 Mutation 
 { 
  
 // spanner.Key can be used to delete a specific set of rows. 
  
 // Delete the Albums with the key values (2,1) and (2,3). 
  
 spanner 
 . 
 Delete 
 ( 
 "Albums" 
 , 
  
 spanner 
 . 
  Key 
 
 { 
 2 
 , 
  
 1 
 }), 
  
 spanner 
 . 
 Delete 
 ( 
 "Albums" 
 , 
  
 spanner 
 . 
  Key 
 
 { 
 2 
 , 
  
 3 
 }), 
  
 // spanner.KeyRange can be used to delete rows with a key in a specific range. 
  
 // Delete a range of rows where the column key is >=3 and <5 
  
 spanner 
 . 
 Delete 
 ( 
 "Singers" 
 , 
  
 spanner 
 . 
 KeyRange 
 { 
 Start 
 : 
  
 spanner 
 . 
  Key 
 
 { 
 3 
 }, 
  
 End 
 : 
  
 spanner 
 . 
  Key 
 
 { 
 5 
 }, 
  
 Kind 
 : 
  
 spanner 
 . 
  ClosedOpen 
 
 }), 
  
 // spanner.AllKeys can be used to delete all the rows in a table. 
  
 // Delete remaining Singers rows, which will also delete the remaining Albums rows since it was 
  
 // defined with ON DELETE CASCADE. 
  
 spanner 
 . 
 Delete 
 ( 
 "Singers" 
 , 
  
 spanner 
 . 
  AllKeys 
 
 ()), 
  
 } 
  
 _ 
 , 
  
 err 
  
 = 
  
 client 
 . 
  Apply 
 
 ( 
 ctx 
 , 
  
 m 
 ) 
  
 return 
  
 err 
 } 
 

Java

Delete rows using the Mutation.delete() method.

This examples uses the KeySet.all() method to delete all the rows in the Albums table. After deleting the rows in the Albums table, the example deletes the rows in the Singers table individually using keys created with the KeySet.singleKey() method.

  static 
  
 void 
  
 deleteExampleData 
 ( 
 DatabaseClient 
  
 dbClient 
 ) 
  
 { 
  
 List<Mutation> 
  
 mutations 
  
 = 
  
 new 
  
 ArrayList 
<> (); 
  
 // KeySet.Builder can be used to delete a specific set of rows. 
  
 // Delete the Albums with the key values (2,1) and (2,3). 
  
 mutations 
 . 
 add 
 ( 
  
 Mutation 
 . 
 delete 
 ( 
  
 "Albums" 
 , 
  
 KeySet 
 . 
 newBuilder 
 (). 
 addKey 
 ( 
 Key 
 . 
 of 
 ( 
 2 
 , 
  
 1 
 )). 
 addKey 
 ( 
 Key 
 . 
 of 
 ( 
 2 
 , 
  
 3 
 )). 
 build 
 ())); 
  
 // KeyRange can be used to delete rows with a key in a specific range. 
  
 // Delete a range of rows where the column key is >=3 and <5 
  
 mutations 
 . 
 add 
 ( 
  
 Mutation 
 . 
 delete 
 ( 
 "Singers" 
 , 
  
 KeySet 
 . 
 range 
 ( 
 KeyRange 
 . 
 closedOpen 
 ( 
 Key 
 . 
 of 
 ( 
 3 
 ), 
  
 Key 
 . 
 of 
 ( 
 5 
 ))))); 
  
 // KeySet.all() can be used to delete all the rows in a table. 
  
 // Delete remaining Singers rows, which will also delete the remaining Albums rows since it was 
  
 // defined with ON DELETE CASCADE. 
  
 mutations 
 . 
 add 
 ( 
 Mutation 
 . 
 delete 
 ( 
 "Singers" 
 , 
  
 KeySet 
 . 
 all 
 ())); 
  
 dbClient 
 . 
 write 
 ( 
 mutations 
 ); 
  
 System 
 . 
 out 
 . 
 printf 
 ( 
 "Records deleted.\n" 
 ); 
 } 
 

Node.js

Delete rows using the table.deleteRows() method.

This example uses the table.deleteRows() method to delete all the rows from the Singers table. The rows in the Albums table are deleted because the Albums table is interleaved in Singers table and is defined with ON DELETE CASCADE .

  // Imports the Google Cloud client library 
 const 
  
 { 
 Spanner 
 } 
  
 = 
  
 require 
 ( 
 ' @google-cloud/spanner 
' 
 ); 
 /** 
 * TODO(developer): Uncomment the following lines before running the sample. 
 */ 
 // const projectId = 'my-project-id'; 
 // const instanceId = 'my-instance'; 
 // const databaseId = 'my-database'; 
 // Creates a client 
 const 
  
 spanner 
  
 = 
  
 new 
  
  Spanner 
 
 ({ 
  
 projectId 
 : 
  
 projectId 
 , 
 }); 
 // Gets a reference to a Cloud Spanner instance and database 
 const 
  
 instance 
  
 = 
  
 spanner 
 . 
 instance 
 ( 
 instanceId 
 ); 
 const 
  
 database 
  
 = 
  
 instance 
 . 
 database 
 ( 
 databaseId 
 ); 
 // Instantiate Spanner table object 
 const 
  
 albumsTable 
  
 = 
  
 database 
 . 
 table 
 ( 
 'Albums' 
 ); 
 // Deletes individual rows from the Albums table. 
 try 
  
 { 
  
 const 
  
 keys 
  
 = 
  
 [ 
  
 [ 
 2 
 , 
  
 1 
 ], 
  
 [ 
 2 
 , 
  
 3 
 ], 
  
 ]; 
  
 await 
  
 albumsTable 
 . 
 deleteRows 
 ( 
 keys 
 ); 
  
 console 
 . 
 log 
 ( 
 'Deleted individual rows in Albums.' 
 ); 
 } 
  
 catch 
  
 ( 
 err 
 ) 
  
 { 
  
 console 
 . 
 error 
 ( 
 'ERROR:' 
 , 
  
 err 
 ); 
 } 
 // Delete a range of rows where the column key is >=3 and <5 
 database 
 . 
  runTransaction 
 
 ( 
 async 
  
 ( 
 err 
 , 
  
 transaction 
 ) 
  
 = 
>  
 { 
  
 if 
  
 ( 
 err 
 ) 
  
 { 
  
 console 
 . 
 error 
 ( 
 err 
 ); 
  
 return 
 ; 
  
 } 
  
 try 
  
 { 
  
 const 
  
 [ 
 rowCount 
 ] 
  
 = 
  
 await 
  
 transaction 
 . 
  runUpdate 
 
 ({ 
  
 sql 
 : 
  
 'DELETE FROM Singers WHERE SingerId >= 3 AND SingerId < 5' 
 , 
  
 }); 
  
 console 
 . 
 log 
 ( 
 ` 
 ${ 
 rowCount 
 } 
 records deleted from Singers.` 
 ); 
  
 } 
  
 catch 
  
 ( 
 err 
 ) 
  
 { 
  
 console 
 . 
 error 
 ( 
 'ERROR:' 
 , 
  
 err 
 ); 
  
 } 
  
 // Deletes remaining rows from the Singers table and the Albums table, 
  
 // because Albums table is defined with ON DELETE CASCADE. 
  
 try 
  
 { 
  
 // The WHERE clause is required for DELETE statements to prevent 
  
 // accidentally deleting all rows in a table. 
  
 // https://cloud.google.com/spanner/docs/dml-syntax#where_clause 
  
 const 
  
 [ 
 rowCount 
 ] 
  
 = 
  
 await 
  
 transaction 
 . 
  runUpdate 
 
 ({ 
  
 sql 
 : 
  
 'DELETE FROM Singers WHERE true' 
 , 
  
 }); 
  
 console 
 . 
 log 
 ( 
 ` 
 ${ 
 rowCount 
 } 
 records deleted from Singers.` 
 ); 
  
 await 
  
 transaction 
 . 
 commit 
 (); 
  
 } 
  
 catch 
  
 ( 
 err 
 ) 
  
 { 
  
 console 
 . 
 error 
 ( 
 'ERROR:' 
 , 
  
 err 
 ); 
  
 } 
  
 finally 
  
 { 
  
 // Close the database when finished. 
  
 await 
  
 database 
 . 
 close 
 (); 
  
 } 
 }); 
 

PHP

Delete rows using the Database::delete() method . The Database::delete() method page includes an example.

Python

Delete rows using the Batch.delete() method.

This example deletes all the rows in the Albums and Singers tables individually using a KeySet object.

  def 
  
 delete_data 
 ( 
 instance_id 
 , 
 database_id 
 ): 
  
 """Deletes sample data from the given database. 
 The database, table, and data must already exist and can be created using 
 `create_database` and `insert_data`. 
 """ 
 spanner_client 
 = 
 spanner 
 . 
 Client 
 () 
 instance 
 = 
 spanner_client 
 . 
 instance 
 ( 
 instance_id 
 ) 
 database 
 = 
 instance 
 . 
 database 
 ( 
 database_id 
 ) 
 # Delete individual rows 
 albums_to_delete 
 = 
 spanner 
 . 
 KeySet 
 ( 
 keys 
 = 
 [[ 
 2 
 , 
 1 
 ], 
 [ 
 2 
 , 
 3 
 ]]) 
 # Delete a range of rows where the column key is >=3 and <5 
 singers_range 
 = 
 spanner 
 . 
 KeyRange 
 ( 
 start_closed 
 = 
 [ 
 3 
 ], 
 end_open 
 = 
 [ 
 5 
 ]) 
 singers_to_delete 
 = 
 spanner 
 . 
 KeySet 
 ( 
 ranges 
 = 
 [ 
 singers_range 
 ]) 
 # Delete remaining Singers rows, which will also delete the remaining 
 # Albums rows because Albums was defined with ON DELETE CASCADE 
 remaining_singers 
 = 
 spanner 
 . 
 KeySet 
 ( 
 all_ 
 = 
 True 
 ) 
 with 
 database 
 . 
 batch 
 () 
 as 
 batch 
 : 
 batch 
 . 
 delete 
 ( 
 "Albums" 
 , 
 albums_to_delete 
 ) 
 batch 
 . 
 delete 
 ( 
 "Singers" 
 , 
 singers_to_delete 
 ) 
 batch 
 . 
 delete 
 ( 
 "Singers" 
 , 
 remaining_singers 
 ) 
 print 
 ( 
 "Deleted data." 
 ) 
 

Ruby

Delete rows using the Client#delete method. The Client#delete page includes an example.

  # project_id  = "Your Google Cloud project ID" 
 # instance_id = "Your Spanner instance ID" 
 # database_id = "Your Spanner database ID" 
 require 
  
 "google/cloud/spanner" 
 spanner 
  
 = 
  
 Google 
 :: 
 Cloud 
 :: 
 Spanner 
 . 
 new 
  
 project 
 : 
  
 project_id 
 client 
  
 = 
  
 spanner 
 . 
 client 
  
 instance_id 
 , 
  
 database_id 
 # Delete individual rows 
 client 
 . 
 delete 
  
 "Albums" 
 , 
  
 [[ 
 2 
 , 
  
 1 
 ] 
 , 
  
 [ 
 2 
 , 
  
 3 
 ]] 
 # Delete a range of rows where the column key is >=3 and <5 
 key_range 
  
 = 
  
 client 
 . 
 range 
  
 3 
 , 
  
 5 
 , 
  
 exclude_end 
 : 
  
 true 
 client 
 . 
 delete 
  
 "Singers" 
 , 
  
 key_range 
 # Delete remaining Singers rows, which will also delete the remaining 
 # Albums rows because Albums was defined with ON DELETE CASCADE 
 client 
 . 
 delete 
  
 "Singers" 
 
Design a Mobile Site
View Site in Mobile | Classic
Share by: