Skip to content

Commit 5463ff7

Browse files
authored
chore(spanner): samples to set transaction options (#1777)
Adds samples that show how to set the isolation level and read lock mode at the Spanner client level and at a transaction level. If it's set at the client level, all RW transactions will set this value. The transaction-level setting allows users to override the client-level setting or to set the values for specific transactions.
1 parent 9dc18c4 commit 5463ff7

5 files changed

Lines changed: 184 additions & 10 deletions

File tree

spanner/Gemfile.lock

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
GEM
22
remote: https://rubygems.org/
33
specs:
4-
addressable (2.8.9)
4+
addressable (2.9.0)
55
public_suffix (>= 2.0.2, < 8.0)
66
base64 (0.3.0)
77
bigdecimal (3.3.1)
@@ -42,27 +42,27 @@ GEM
4242
google-cloud-env (2.3.1)
4343
base64 (~> 0.2)
4444
faraday (>= 1.0, < 3.a)
45-
google-cloud-errors (1.5.0)
46-
google-cloud-spanner (2.35.0)
45+
google-cloud-errors (1.6.0)
46+
google-cloud-spanner (2.36.0)
4747
bigdecimal (~> 3.0)
4848
concurrent-ruby (~> 1.0)
4949
google-cloud-core (~> 1.7)
5050
google-cloud-spanner-admin-database-v1 (~> 1.4)
5151
google-cloud-spanner-admin-instance-v1 (~> 1.6)
5252
google-cloud-spanner-v1 (~> 1.6)
53-
google-cloud-spanner-admin-database-v1 (1.11.1)
53+
google-cloud-spanner-admin-database-v1 (1.13.1)
5454
gapic-common (~> 1.2)
5555
google-cloud-errors (~> 1.0)
5656
grpc-google-iam-v1 (~> 1.11)
5757
google-cloud-spanner-admin-instance-v1 (1.6.0)
5858
gapic-common (>= 0.25.0, < 2.a)
5959
google-cloud-errors (~> 1.0)
6060
grpc-google-iam-v1 (~> 1.1)
61-
google-cloud-spanner-v1 (1.15.0)
61+
google-cloud-spanner-v1 (1.18.0)
6262
gapic-common (~> 1.2)
6363
google-cloud-errors (~> 1.0)
6464
google-logging-utils (0.2.0)
65-
google-protobuf (4.34.0)
65+
google-protobuf (4.34.1)
6666
bigdecimal
6767
rake (~> 13.3)
6868
googleapis-common-protos (1.7.0)
@@ -79,26 +79,26 @@ GEM
7979
multi_json (~> 1.11)
8080
os (>= 0.9, < 2.0)
8181
signet (>= 0.16, < 2.a)
82-
grpc (1.78.1)
82+
grpc (1.80.0)
8383
google-protobuf (>= 3.25, < 5.0)
8484
googleapis-common-protos-types (~> 1.0)
8585
grpc-google-iam-v1 (1.11.0)
8686
google-protobuf (>= 3.18, < 5.a)
8787
googleapis-common-protos (~> 1.7.0)
8888
grpc (~> 1.41)
8989
httpclient (2.8.3)
90-
json (2.19.1)
90+
json (2.19.5)
9191
jwt (3.1.2)
9292
base64
9393
logger (1.7.0)
9494
mini_mime (1.1.5)
95-
multi_json (1.19.1)
95+
multi_json (1.21.1)
9696
mutex_m (0.3.0)
9797
net-http (0.9.1)
9898
uri (>= 0.11.1)
9999
os (1.1.4)
100100
public_suffix (7.0.5)
101-
rake (13.3.1)
101+
rake (13.4.2)
102102
representable (3.2.0)
103103
declarative (< 0.1.0)
104104
trailblazer-option (>= 0.1.1, < 0.2.0)

spanner/spanner_isolation_level.rb

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
# Copyright 2026 Google, Inc
2+
#
3+
# Licensed under the Apache License, Version 2.0 (the "License");
4+
# you may not use this file except in compliance with the License.
5+
# You may obtain a copy of the License at
6+
#
7+
# http://www.apache.org/licenses/LICENSE-2.0
8+
#
9+
# Unless required by applicable law or agreed to in writing, software
10+
# distributed under the License is distributed on an "AS IS" BASIS,
11+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
# See the License for the specific language governing permissions and
13+
# limitations under the License.
14+
15+
# [START spanner_isolation_level]
16+
require "google/cloud/spanner"
17+
18+
def spanner_isolation_level project_id:, instance_id:, database_id:
19+
# Instantiates a client with isolation_level: :SERIALIZABLE
20+
spanner = Google::Cloud::Spanner.new project: project_id
21+
client = spanner.client instance_id, database_id, isolation_level: :SERIALIZABLE
22+
23+
# Overrides isolation_level to :REPEATABLE_READ at transaction level
24+
client.transaction isolation_level: :REPEATABLE_READ do |tx|
25+
results = tx.execute_query "SELECT AlbumTitle FROM Albums WHERE SingerId = 1 AND AlbumId = 1"
26+
27+
results.rows.each do |row|
28+
puts "AlbumTitle: #{row[:AlbumTitle]}"
29+
end
30+
31+
row_count = tx.execute_update "UPDATE Albums SET AlbumTitle = 'A New Title' WHERE SingerId = 1 AND AlbumId = 1"
32+
33+
puts "#{row_count} records updated."
34+
end
35+
end
36+
# [END spanner_isolation_level]

spanner/spanner_read_lock_mode.rb

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
# Copyright 2026 Google, Inc
2+
#
3+
# Licensed under the Apache License, Version 2.0 (the "License");
4+
# you may not use this file except in compliance with the License.
5+
# You may obtain a copy of the License at
6+
#
7+
# http://www.apache.org/licenses/LICENSE-2.0
8+
#
9+
# Unless required by applicable law or agreed to in writing, software
10+
# distributed under the License is distributed on an "AS IS" BASIS,
11+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
# See the License for the specific language governing permissions and
13+
# limitations under the License.
14+
15+
# [START spanner_read_lock_mode]
16+
require "google/cloud/spanner"
17+
18+
def spanner_read_lock_mode project_id:, instance_id:, database_id:
19+
# Instantiates a client with read_lock_mode: :OPTIMISTIC
20+
spanner = Google::Cloud::Spanner.new project: project_id
21+
client = spanner.client instance_id, database_id, read_lock_mode: :OPTIMISTIC
22+
23+
# Overrides read_lock_mode to :PESSIMISTIC at transaction level
24+
client.transaction read_lock_mode: :PESSIMISTIC do |tx|
25+
results = tx.execute_query "SELECT AlbumTitle FROM Albums WHERE SingerId = 2 AND AlbumId = 1"
26+
27+
results.rows.each do |row|
28+
puts "AlbumTitle: #{row[:AlbumTitle]}"
29+
end
30+
31+
row_count = tx.execute_update "UPDATE Albums SET AlbumTitle = 'A New Title' WHERE SingerId = 2 AND AlbumId = 1"
32+
33+
puts "#{row_count} records updated."
34+
end
35+
end
36+
# [END spanner_read_lock_mode]
Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
# Copyright 2026 Google, Inc
2+
#
3+
# Licensed under the Apache License, Version 2.0 (the "License");
4+
# you may not use this file except in compliance with the License.
5+
# You may obtain a copy of the License at
6+
#
7+
# http://www.apache.org/licenses/LICENSE-2.0
8+
#
9+
# Unless required by applicable law or agreed to in writing, software
10+
# distributed under the License is distributed on an "AS IS" BASIS,
11+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
# See the License for the specific language governing permissions and
13+
# limitations under the License.
14+
15+
require_relative "../spanner_isolation_level"
16+
require "rspec"
17+
require "google/cloud/spanner"
18+
19+
describe "Spanner Isolation Level Options" do
20+
it "runs isolation level snippet successfully" do
21+
if ENV["GOOGLE_CLOUD_SPANNER_TEST_INSTANCE"].nil? || ENV["GOOGLE_CLOUD_SPANNER_PROJECT"].nil?
22+
skip "GOOGLE_CLOUD_SPANNER_TEST_INSTANCE and/or GOOGLE_CLOUD_SPANNER_PROJECT not defined"
23+
end
24+
25+
@project_id = ENV["GOOGLE_CLOUD_SPANNER_PROJECT"]
26+
@instance_id = ENV["GOOGLE_CLOUD_SPANNER_TEST_INSTANCE"]
27+
@seed = SecureRandom.hex 8
28+
@database_id = "test_db_#{@seed}"
29+
@spanner = Google::Cloud::Spanner.new project: @project_id
30+
@instance = @spanner.instance @instance_id
31+
32+
unless @instance.database @database_id
33+
real_stdout = $stdout
34+
$stdout = StringIO.new
35+
create_database project_id: @project_id,
36+
instance_id: @instance_id,
37+
database_id: @database_id
38+
$stdout = real_stdout
39+
end
40+
41+
client = @spanner.client @instance_id, @database_id
42+
client.insert "Singers", [{ SingerId: 1, FirstName: "Test" }]
43+
client.insert "Albums", [{ SingerId: 1, AlbumId: 1, AlbumTitle: "Old Title" }]
44+
45+
expect {
46+
spanner_isolation_level project_id: @project_id, instance_id: @instance_id, database_id: @database_id
47+
}.to output(/AlbumTitle: Old Title\n1 records updated./).to_stdout
48+
49+
@instance.database(@database_id).drop
50+
end
51+
end
Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
# Copyright 2026 Google, Inc
2+
#
3+
# Licensed under the Apache License, Version 2.0 (the "License");
4+
# you may not use this file except in compliance with the License.
5+
# You may obtain a copy of the License at
6+
#
7+
# http://www.apache.org/licenses/LICENSE-2.0
8+
#
9+
# Unless required by applicable law or agreed to in writing, software
10+
# distributed under the License is distributed on an "AS IS" BASIS,
11+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
# See the License for the specific language governing permissions and
13+
# limitations under the License.
14+
15+
require_relative "../spanner_read_lock_mode"
16+
require "rspec"
17+
require "google/cloud/spanner"
18+
19+
describe "Spanner Read Lock Mode Options" do
20+
it "runs read lock mode snippet successfully" do
21+
if ENV["GOOGLE_CLOUD_SPANNER_TEST_INSTANCE"].nil? || ENV["GOOGLE_CLOUD_SPANNER_PROJECT"].nil?
22+
skip "GOOGLE_CLOUD_SPANNER_TEST_INSTANCE and/or GOOGLE_CLOUD_SPANNER_PROJECT not defined"
23+
end
24+
25+
@project_id = ENV["GOOGLE_CLOUD_SPANNER_PROJECT"]
26+
@instance_id = ENV["GOOGLE_CLOUD_SPANNER_TEST_INSTANCE"]
27+
@seed = SecureRandom.hex 8
28+
@database_id = "test_db_#{@seed}"
29+
@spanner = Google::Cloud::Spanner.new project: @project_id
30+
@instance = @spanner.instance @instance_id
31+
32+
unless @instance.database @database_id
33+
real_stdout = $stdout
34+
$stdout = StringIO.new
35+
create_database project_id: @project_id,
36+
instance_id: @instance_id,
37+
database_id: @database_id
38+
$stdout = real_stdout
39+
end
40+
41+
client = @spanner.client @instance_id, @database_id
42+
client.insert "Singers", [{ SingerId: 2, FirstName: "Test" }]
43+
client.insert "Albums", [{ SingerId: 2, AlbumId: 1, AlbumTitle: "Old Title" }]
44+
45+
expect {
46+
spanner_read_lock_mode project_id: @project_id, instance_id: @instance_id, database_id: @database_id
47+
}.to output(/AlbumTitle: Old Title\n1 records updated./).to_stdout
48+
49+
@instance.database(@database_id).drop
50+
end
51+
end

0 commit comments

Comments
 (0)