Read/write transaction

Use a read/write transaction.

Explore further

For detailed documentation that includes this code sample, see the following:

Code sample

C++

To learn how to install and use the client library for Spanner, see Spanner client libraries .

To authenticate to Spanner, set up Application Default Credentials. For more information, see Set up authentication for a local development environment .

  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#

To learn how to install and use the client library for Spanner, see Spanner client libraries .

To authenticate to Spanner, set up Application Default Credentials. For more information, see Set up authentication for a local development environment .

  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 
 ; 
  
 } 
 } 
 

Go

To learn how to install and use the client library for Spanner, see Spanner client libraries .

To authenticate to Spanner, set up Application Default Credentials. For more information, see Set up authentication for a local development environment .

  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

To learn how to install and use the client library for Spanner, see Spanner client libraries .

To authenticate to Spanner, set up Application Default Credentials. For more information, see Set up authentication for a local development environment .

  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

To learn how to install and use the client library for Spanner, see Spanner client libraries .

To authenticate to Spanner, set up Application Default Credentials. For more information, see Set up authentication for a local development environment .

  // 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

To learn how to install and use the client library for Spanner, see Spanner client libraries .

To authenticate to Spanner, set up Application Default Credentials. For more information, see Set up authentication for a local development environment .

  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

To learn how to install and use the client library for Spanner, see Spanner client libraries .

To authenticate to Spanner, set up Application Default Credentials. For more information, see Set up authentication for a local development environment .

  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

To learn how to install and use the client library for Spanner, see Spanner client libraries .

To authenticate to Spanner, set up Application Default Credentials. For more information, see Set up authentication for a local development environment .

  # 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" 
 

What's next

To search and filter code samples for other Google Cloud products, see the Google Cloud sample browser .

Create a Mobile Website
View Site in Mobile | Classic
Share by: