Skip to content

Commit 60ee659

Browse files
authored
docs: add sample for PROTO columns (#1918)
Adds a sample for using PROTO columns with the JDBC driver. Fixes #1916
1 parent ee6082f commit 60ee659

File tree

9 files changed

+1341
-2
lines changed

9 files changed

+1341
-2
lines changed

README.md

+13-2
Original file line numberDiff line numberDiff line change
@@ -155,8 +155,19 @@ activate the `shade` profile like this:
155155
mvn package -Pshade
156156
```
157157

158-
159-
158+
## Samples
159+
160+
See the [samples](/samples) directory for various examples for using the Spanner JDBC driver.
161+
162+
- [snippets](/samples/snippets): Contains small code snippets for commonly used JDBC and Spanner
163+
features. Refer to these snippets for examples on how to execute DDL and DML batches, use various
164+
data types with the JDBC driver, execute various types of transactions (read/write, read-only,
165+
Partitioned DML), use request and transaction tags, etc.
166+
- [spring-data-jdbc](/samples/spring-data-jdbc): Contains a sample application that uses Spring Data
167+
JDBC in combination with a Spanner PostgreSQL database.
168+
- [spring-data-mybatis](/samples/spring-data-mybatis): Contains a sample application that uses
169+
Spring Data MyBatis in combination with a Spanner PostgreSQL database.
170+
- [quickperf](/samples/quickperf): Contains a simple benchmarking application.
160171

161172

162173
## Troubleshooting

samples/snapshot/pom.xml

+1
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
<groupId>com.google.cloud.samples</groupId>
1616
<artifactId>shared-configuration</artifactId>
1717
<version>1.2.2</version>
18+
<relativePath/>
1819
</parent>
1920

2021
<properties>

samples/snippets/pom.xml

+7
Original file line numberDiff line numberDiff line change
@@ -122,6 +122,13 @@
122122
</archive>
123123
</configuration>
124124
</plugin>
125+
<plugin>
126+
<groupId>org.apache.maven.plugins</groupId>
127+
<artifactId>maven-checkstyle-plugin</artifactId>
128+
<configuration>
129+
<excludes>**/SingerProto.java</excludes>
130+
</configuration>
131+
</plugin>
125132
</plugins>
126133
</build>
127134
</project>

samples/snippets/src/main/java/com/example/spanner/jdbc/JdbcSample.java

+105
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,8 @@
1616

1717
package com.example.spanner.jdbc;
1818

19+
import com.example.spanner.jdbc.SingerProto.Genre;
20+
import com.example.spanner.jdbc.SingerProto.SingerInfo;
1921
import com.google.api.gax.core.NoCredentialsProvider;
2022
import com.google.api.gax.grpc.InstantiatingGrpcChannelProvider;
2123
import com.google.cloud.spanner.DatabaseId;
@@ -29,13 +31,17 @@
2931
import com.google.cloud.spanner.admin.database.v1.DatabaseAdminClient;
3032
import com.google.cloud.spanner.admin.database.v1.DatabaseAdminSettings;
3133
import com.google.cloud.spanner.jdbc.CloudSpannerJdbcConnection;
34+
import com.google.cloud.spanner.jdbc.ProtoEnumType;
35+
import com.google.cloud.spanner.jdbc.ProtoMessageType;
3236
import com.google.common.base.Strings;
3337
import com.google.common.collect.ImmutableList;
3438
import com.google.spanner.admin.database.v1.CreateDatabaseRequest;
3539
import com.google.spanner.admin.database.v1.DatabaseDialect;
3640
import com.google.spanner.admin.instance.v1.InstanceName;
3741
import com.google.spanner.v1.DatabaseName;
3842
import io.grpc.ManagedChannelBuilder;
43+
import java.io.IOException;
44+
import java.io.InputStream;
3945
import java.sql.Connection;
4046
import java.sql.DriverManager;
4147
import java.sql.PreparedStatement;
@@ -1576,6 +1582,98 @@ static void arrayOfStructAsQueryParameter(
15761582
}
15771583
}
15781584

1585+
static void protoColumns(
1586+
final String project,
1587+
final String instance,
1588+
final String database,
1589+
final Properties properties) throws SQLException, IOException {
1590+
try (Connection connection =
1591+
DriverManager.getConnection(
1592+
String.format(
1593+
"jdbc:cloudspanner:/projects/%s/instances/%s/databases/%s",
1594+
project, instance, database),
1595+
properties)) {
1596+
// Create a PROTO BUNDLE and a table.
1597+
try (Statement statement = connection.createStatement();
1598+
InputStream protoDescriptors = JdbcSample.class.getClassLoader()
1599+
.getResourceAsStream("com/example/spanner/jdbc/descriptors.pb")) {
1600+
if (protoDescriptors == null) {
1601+
throw new IllegalArgumentException("proto descriptors not found");
1602+
}
1603+
1604+
// Unwrap the CloudSpannerJdbcConnection interface to set the proto
1605+
// descriptors that should be used for the next DDL statements.
1606+
connection
1607+
.unwrap(CloudSpannerJdbcConnection.class)
1608+
.setProtoDescriptors(protoDescriptors);
1609+
// Execute the DDL statements as one batch.
1610+
// This will reduce execution time compared to executing each statement
1611+
// sequentially.
1612+
statement.addBatch("CREATE PROTO BUNDLE (\n"
1613+
+ "examples.spanner.music.SingerInfo,\n"
1614+
+ "examples.spanner.music.Genre,\n"
1615+
+ ")");
1616+
statement.addBatch("CREATE TABLE SingersWithProto (\n"
1617+
+ " SingerId INT64 NOT NULL,\n"
1618+
+ " SingerInfo examples.spanner.music.SingerInfo,\n"
1619+
+ " SingerGenre examples.spanner.music.Genre,\n"
1620+
+ ") PRIMARY KEY (SingerId)");
1621+
statement.executeBatch();
1622+
}
1623+
1624+
// Insert a couple of rows using a prepared statement.
1625+
try (PreparedStatement statement = connection.prepareStatement(
1626+
"INSERT INTO SingersWithProto "
1627+
+ "(SingerId, SingerInfo, SingerGenre) "
1628+
+ "VALUES (?, ?, ?)")) {
1629+
int param = 0;
1630+
statement.setLong(++param, 1L);
1631+
statement.setObject(++param,
1632+
SingerInfo.newBuilder()
1633+
.setGenre(Genre.ROCK)
1634+
.setBirthDate("1998-07-04")
1635+
.setSingerId(1L)
1636+
.setNationality("ES")
1637+
.build(), ProtoMessageType.VENDOR_TYPE_NUMBER);
1638+
statement.setObject(++param, Genre.ROCK,
1639+
ProtoEnumType.VENDOR_TYPE_NUMBER);
1640+
statement.addBatch();
1641+
1642+
param = 0;
1643+
statement.setLong(++param, 2L);
1644+
statement.setObject(++param,
1645+
SingerInfo.newBuilder()
1646+
.setGenre(Genre.POP)
1647+
.setBirthDate("2001-12-03")
1648+
.setSingerId(2L)
1649+
.setNationality("FO")
1650+
.build(), ProtoMessageType.VENDOR_TYPE_NUMBER);
1651+
statement.setObject(++param, Genre.POP,
1652+
ProtoEnumType.VENDOR_TYPE_NUMBER);
1653+
statement.addBatch();
1654+
1655+
int[] updateCounts = statement.executeBatch();
1656+
System.out.printf("Inserted %d singers\n",
1657+
Arrays.stream(updateCounts).sum());
1658+
}
1659+
1660+
// Read the inserted rows.
1661+
try (ResultSet resultSet = connection.createStatement()
1662+
.executeQuery("SELECT * FROM SingersWithProto")) {
1663+
while (resultSet.next()) {
1664+
long singerId = resultSet.getLong("SingerId");
1665+
// Proto messages and proto enums can be retrieved with the
1666+
// ResultSet#getObject(int, Class) method.
1667+
// The Spanner JDBC driver automatically deserializes
1668+
// and converts the column to the Java class representation.
1669+
SingerInfo info = resultSet.getObject("SingerInfo", SingerInfo.class);
1670+
Genre genre = resultSet.getObject("SingerGenre", Genre.class);
1671+
System.out.printf("%d:\n%s\n%s\n", singerId, info, genre);
1672+
}
1673+
}
1674+
}
1675+
}
1676+
15791677
/** The expected number of command line arguments. */
15801678
private static final int NUM_EXPECTED_ARGS = 3;
15811679

@@ -1761,6 +1859,13 @@ static boolean runGoogleSQLSample(
17611859
database.getDatabase(),
17621860
createProperties());
17631861
return true;
1862+
case "protocolumns":
1863+
protoColumns(
1864+
database.getInstanceId().getProject(),
1865+
database.getInstanceId().getInstance(),
1866+
database.getDatabase(),
1867+
createProperties());
1868+
return true;
17641869
default:
17651870
return false;
17661871
}

0 commit comments

Comments
 (0)