Skip to content

Commit a2bb97a

Browse files
committed
docs: add samples for transaction isolation level
1 parent 3476106 commit a2bb97a

File tree

3 files changed

+178
-0
lines changed

3 files changed

+178
-0
lines changed

samples/snippets/pom.xml

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,13 @@
2323
<!-- [START spanner-jdbc_install_with_bom] -->
2424
<dependencyManagement>
2525
<dependencies>
26+
<dependency>
27+
<groupId>com.google.cloud</groupId>
28+
<artifactId>google-cloud-spanner-bom</artifactId>
29+
<version>6.91.1</version>
30+
<type>pom</type>
31+
<scope>import</scope>
32+
</dependency>
2633
<dependency>
2734
<groupId>com.google.cloud</groupId>
2835
<artifactId>libraries-bom</artifactId>
@@ -37,6 +44,7 @@
3744
<dependency>
3845
<groupId>com.google.cloud</groupId>
3946
<artifactId>google-cloud-spanner-jdbc</artifactId>
47+
<version>2.29.1</version>
4048
<exclusions>
4149
<exclusion>
4250
<groupId>com.google.api.grpc</groupId>
Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,73 @@
1+
/*
2+
* Copyright 2025 Google LLC
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package com.example.spanner.jdbc;
18+
19+
import java.sql.Connection;
20+
import java.sql.DriverManager;
21+
import java.sql.PreparedStatement;
22+
import java.sql.ResultSet;
23+
import java.sql.SQLException;
24+
import java.util.Properties;
25+
26+
final class IsolationLevel {
27+
28+
static void isolationLevel(
29+
final String project,
30+
final String instance,
31+
final String database,
32+
final Properties properties)
33+
throws SQLException {
34+
String url = String.format(
35+
"jdbc:cloudspanner:/projects/%s/instances/%s/databases/%s",
36+
project, instance, database);
37+
try (Connection connection = DriverManager.getConnection(url, properties)) {
38+
connection.setAutoCommit(false);
39+
40+
// Spanner supports setting the isolation level to:
41+
// 1. TRANSACTION_SERIALIZABLE (this is the default)
42+
// 2. TRANSACTION_REPEATABLE_READ
43+
44+
// The following line sets the default isolation level that will be used
45+
// for all read/write transactions on this connection.
46+
connection.setTransactionIsolation(
47+
Connection.TRANSACTION_REPEATABLE_READ);
48+
49+
// This query will not take any locks when using
50+
// isolation level repeatable read.
51+
try (ResultSet resultSet = connection
52+
.createStatement()
53+
.executeQuery("SELECT SingerId, Active "
54+
+ "FROM Singers "
55+
+ "ORDER BY LastName")) {
56+
while (resultSet.next()) {
57+
try (PreparedStatement statement = connection.prepareStatement(
58+
"INSERT OR UPDATE INTO SingerHistory "
59+
+ "(SingerId, Active, CreatedAt) "
60+
+ "VALUES (?, ?, CURRENT_TIMESTAMP)")) {
61+
statement.setLong(1, resultSet.getLong(1));
62+
statement.setBoolean(2, resultSet.getBoolean(2));
63+
statement.executeUpdate();
64+
}
65+
}
66+
}
67+
connection.commit();
68+
}
69+
}
70+
71+
private IsolationLevel() {
72+
}
73+
}
Lines changed: 97 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,97 @@
1+
/*
2+
* Copyright 2025 Google LLC
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package com.example.spanner.jdbc;
18+
19+
import static com.example.spanner.jdbc.IsolationLevel.isolationLevel;
20+
import static org.junit.Assume.assumeTrue;
21+
22+
import java.sql.Connection;
23+
import java.sql.DriverManager;
24+
import java.sql.SQLException;
25+
import java.sql.Statement;
26+
import java.util.Properties;
27+
import org.junit.AfterClass;
28+
import org.junit.BeforeClass;
29+
import org.junit.Test;
30+
import org.junit.runner.RunWith;
31+
import org.junit.runners.JUnit4;
32+
import org.testcontainers.DockerClientFactory;
33+
import org.testcontainers.containers.GenericContainer;
34+
import org.testcontainers.containers.wait.strategy.Wait;
35+
import org.testcontainers.images.PullPolicy;
36+
import org.testcontainers.utility.DockerImageName;
37+
38+
@RunWith(JUnit4.class)
39+
public class IsolationLevelTest {
40+
41+
private static GenericContainer<?> emulator;
42+
43+
private static final String PROJECT = "emulator-project";
44+
private static final String INSTANCE = "my-instance";
45+
private static final String DATABASE = "my-database";
46+
private static final Properties PROPERTIES = new Properties();
47+
48+
@BeforeClass
49+
public static void setupEmulator() throws Exception {
50+
assumeTrue("This test requires Docker", DockerClientFactory.instance().isDockerAvailable());
51+
52+
emulator =
53+
new GenericContainer<>(DockerImageName.parse("gcr.io/cloud-spanner-emulator/emulator"));
54+
emulator.withImagePullPolicy(PullPolicy.alwaysPull());
55+
emulator.addExposedPort(9010);
56+
emulator.setWaitStrategy(Wait.forListeningPorts(9010));
57+
emulator.start();
58+
59+
PROPERTIES.setProperty("endpoint",
60+
String.format("localhost:%d", emulator.getMappedPort(9010)));
61+
PROPERTIES.setProperty("autoConfigEmulator", "true");
62+
63+
String url = String.format(
64+
"jdbc:cloudspanner:/projects/%s/instances/%s/databases/%s",
65+
PROJECT, INSTANCE, DATABASE);
66+
try (Connection connection = DriverManager.getConnection(url, PROPERTIES)) {
67+
try (Statement statement = connection.createStatement()) {
68+
statement.addBatch(
69+
"CREATE TABLE Singers ("
70+
+ "SingerId INT64 PRIMARY KEY, "
71+
+ "FirstName STRING(MAX), "
72+
+ "LastName STRING(MAX), "
73+
+ "Active BOOL)");
74+
statement.addBatch(
75+
"CREATE TABLE SingerHistory ("
76+
+ "SingerId INT64, "
77+
+ "Active BOOL, "
78+
+ "CreatedAt TIMESTAMP) "
79+
+ "PRIMARY KEY (SingerId, CreatedAt)");
80+
statement.executeBatch();
81+
}
82+
}
83+
}
84+
85+
@AfterClass
86+
public static void stopEmulator() {
87+
if (emulator != null) {
88+
emulator.stop();
89+
}
90+
}
91+
92+
@Test
93+
public void testIsolationLevel() throws SQLException {
94+
isolationLevel("emulator-project", "my-instance", "my-database", PROPERTIES);
95+
}
96+
97+
}

0 commit comments

Comments
 (0)