Skip to content

Commit

Permalink
Merge branch 'spring-data-jdbc-sample' of github.com:googleapis/java-…
Browse files Browse the repository at this point in the history
…spanner-jdbc into spring-data-jdbc-sample
  • Loading branch information
olavloite committed Sep 8, 2023
2 parents 1a4c98c + 458e375 commit 889b310
Show file tree
Hide file tree
Showing 13 changed files with 95 additions and 29 deletions.
4 changes: 2 additions & 2 deletions .github/.OwlBot.lock.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -13,5 +13,5 @@
# limitations under the License.
docker:
image: gcr.io/cloud-devrel-public-resources/owlbot-java:latest
digest: sha256:3a95f1b9b1102865ca551b76be51d2bdb850900c4db2f6d79269e7af81ac8f84
# created: 2023-07-27T18:37:44.251188775Z
digest: sha256:88ba8dcc5c2c7792e1c3511381f4ab329002a1c42c512f66ca87ced572dfbf9f
# created: 2023-09-05T18:54:42.225408832Z
12 changes: 12 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,17 @@
# Changelog

## [2.12.0](https://github.com/googleapis/java-spanner-jdbc/compare/v2.11.9...v2.12.0) (2023-08-28)


### Features

* Return generated keys ([#1310](https://github.com/googleapis/java-spanner-jdbc/issues/1310)) ([9b5ab37](https://github.com/googleapis/java-spanner-jdbc/commit/9b5ab377587de09004474cb1cf488919fc83d6cb))


### Bug Fixes

* Session leak for invalid update ([#1323](https://github.com/googleapis/java-spanner-jdbc/issues/1323)) ([a7d0fbb](https://github.com/googleapis/java-spanner-jdbc/commit/a7d0fbb529ff71b45d6ddbbad8fc3be43e7c966f))

## [2.11.9](https://github.com/googleapis/java-spanner-jdbc/compare/v2.11.8...v2.11.9) (2023-08-21)


Expand Down
2 changes: 1 addition & 1 deletion pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<artifactId>google-cloud-spanner-jdbc</artifactId>
<version>2.11.10-SNAPSHOT</version><!-- {x-version-update:google-cloud-spanner-jdbc:current} -->
<version>2.12.1-SNAPSHOT</version><!-- {x-version-update:google-cloud-spanner-jdbc:current} -->
<packaging>jar</packaging>
<name>Google Cloud Spanner JDBC</name>
<url>https://github.com/googleapis/java-spanner-jdbc</url>
Expand Down
5 changes: 4 additions & 1 deletion renovate.json
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,10 @@
":maintainLockFilesDisabled",
":autodetectPinVersions"
],
"ignorePaths": [".kokoro/requirements.txt"],
"ignorePaths": [
".kokoro/requirements.txt",
".github/workflows/**"
],
"packageRules": [
{
"packagePatterns": [
Expand Down
2 changes: 1 addition & 1 deletion samples/install-without-bom/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@
<dependency>
<groupId>com.google.cloud</groupId>
<artifactId>google-cloud-spanner-jdbc</artifactId>
<version>2.11.9</version>
<version>2.12.0</version>
</dependency>
<!-- [END spanner-jdbc_install_without_bom] -->

Expand Down
2 changes: 1 addition & 1 deletion samples/snapshot/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@
<dependency>
<groupId>com.google.cloud</groupId>
<artifactId>google-cloud-spanner-jdbc</artifactId>
<version>2.11.10-SNAPSHOT</version>
<version>2.12.1-SNAPSHOT</version>
</dependency>
<!-- {x-version-update-end} -->

Expand Down
17 changes: 2 additions & 15 deletions samples/snippets/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@

<!--
The parent pom defines common style checks and testing strategies for our samples.
Removing or replacing it should not affect the execution of the samples in anyway.
Removing or replacing it should not affect the execution of the samples in any way.
-->
<parent>
<groupId>com.google.cloud.samples</groupId>
Expand Down Expand Up @@ -42,19 +42,6 @@
<groupId>com.google.cloud</groupId>
<artifactId>google-cloud-spanner-jdbc</artifactId>
</dependency>
<!-- [END spanner-jdbc_install_with_bom] -->

<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.13.2</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>com.google.truth</groupId>
<artifactId>truth</artifactId>
<version>1.1.5</version>
<scope>test</scope>
</dependency>
</dependencies>
<!-- [END spanner-jdbc_install_with_bom] -->
</project>
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,14 @@ public Application(

@Override
public void run(String... args) {
// databaseSeeder.dropDatabaseSchemaIfExists();

// Set the system property 'drop_schema' to true to drop any existing database
// schema when the application is executed.
if (Boolean.parseBoolean(System.getProperty("drop_schema", "false"))) {
logger.info("Dropping existing schema if it exists");
databaseSeeder.dropDatabaseSchemaIfExists();
}

logger.info("Creating database schema if it does not already exist");
databaseSeeder.createDatabaseSchemaIfNotExists();
logger.info("Deleting existing test data");
Expand Down Expand Up @@ -107,5 +114,13 @@ public void run(String... args) {
for (Singer singer : singerRepository.findSingersByLastNameStartingWith("J")) {
logger.info("\t{}", singer.getFullName());
}

// The singerService.listSingersWithLastNameStartingWith(..) method uses a read-only
// transaction. You should prefer read-only transactions to read/write transactions whenever
// possible, as read-only transactions do not take locks.
logger.info("All singers with a last name starting with an 'A', 'B', or 'C'.");
for (Singer singer : singerService.listSingersWithLastNameStartingWith("A", "B", "C")) {
logger.info("\t{}", singer.getFullName());
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -16,9 +16,13 @@

package com.google.cloud.spanner.sample;

import com.google.cloud.spanner.jdbc.JdbcSqlException;
import com.google.rpc.Code;
import java.util.Objects;
import javax.annotation.Nonnull;
import org.springframework.context.annotation.Configuration;
import org.springframework.dao.DataAccessException;
import org.springframework.dao.IncorrectResultSizeDataAccessException;
import org.springframework.data.jdbc.repository.config.AbstractJdbcConfiguration;
import org.springframework.data.relational.core.dialect.Dialect;
import org.springframework.data.relational.core.dialect.PostgresDialect;
Expand Down Expand Up @@ -53,7 +57,25 @@ public static boolean isCloudSpannerPG(JdbcOperations operations) {
if (Objects.equals(1L, value)) {
return true;
}
} catch (Throwable ignore) {
} catch (IncorrectResultSizeDataAccessException exception) {
// This indicates that it is a valid Cloud Spanner database, but not one that uses the
// PostgreSQL dialect.
throw new RuntimeException(
"The selected Cloud Spanner database does not use the PostgreSQL dialect");
} catch (DataAccessException exception) {
if (exception.getCause() instanceof JdbcSqlException jdbcSqlException) {
if (jdbcSqlException.getCode() == Code.PERMISSION_DENIED
|| jdbcSqlException.getCode() == Code.NOT_FOUND) {
throw new RuntimeException(
"Failed to get the dialect of the Cloud Spanner database. "
+ "Please check that the selected database exists and that you have permission to access it. "
+ "Cause: "
+ exception.getCause().getMessage(),
exception.getCause());
}
}
// ignore and fall through
} catch (Throwable exception) {
// ignore and fall through
}
return false;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,17 +19,25 @@
import org.springframework.data.relational.core.mapping.Column;
import org.springframework.data.relational.core.mapping.Table;

/**
* The "tracks" table is interleaved in "albums". That means that the first part of the primary key
* (the "id" column) references the Album that this Track belongs to. That again means that we do
* not auto-generate the id for this entity. We can achieve this by adding an extra property,
* albumId, that is mapped to the "id" column. We can then manually set an albumId value before
* inserting the record in the database.
*/
@Table("tracks")
public class Track extends AbstractEntity {

/**
* We need to map this to the ID column to be able to explicitly set it, instead of letting Spring
* Data generate it. This is necessary, because Track is interleaved in Album. That again means
* that we must use the ID value of the Album for a Track.
* We need to map this to the "id" column to be able to explicitly set it, instead of letting
* Spring Data generate it. This is necessary, because Track is interleaved in Album. That again
* means that we must use the ID value of the Album for a Track.
*/
@Column("id")
private Long albumId;

/** This is the second part of the primary key of a Track. */
private int trackNumber;

private String title;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,8 @@
import com.google.cloud.spanner.sample.entities.Singer;
import com.google.cloud.spanner.sample.repositories.AlbumRepository;
import com.google.cloud.spanner.sample.repositories.SingerRepository;
import com.google.common.collect.ImmutableList;
import java.util.List;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

Expand All @@ -37,11 +39,29 @@ public SingerService(SingerRepository singerRepository, AlbumRepository albumRep
/** Creates a singer and a list of albums in a transaction. */
@Transactional
public Singer createSingerAndAlbums(Singer singer, Album... albums) {
// Saving a singer will return an updated singer entity that has the primary key value set.
singer = singerRepository.save(singer);
for (Album album : albums) {
// Set the singerId that was generated on the Album before saving it.
album.setSingerId(singer.getId());
albumRepository.save(album);
}
return singer;
}

/**
* Searches for all singers that have a last name starting with any of the given prefixes. This
* method uses a read-only transaction. Read-only transactions should be preferred to read/write
* transactions whenever possible, as read-only transactions do not take locks.
*/
@Transactional(readOnly = true)
public List<Singer> listSingersWithLastNameStartingWith(String... prefixes) {
ImmutableList.Builder<Singer> result = ImmutableList.builder();
// This is not the most efficient way to search for this, but the main purpose of this method is
// to show how to use read-only transactions.
for (String prefix : prefixes) {
result.addAll(singerRepository.findSingersByLastNameStartingWith(prefix));
}
return result.build();
}
}
3 changes: 1 addition & 2 deletions synth.metadata
Original file line number Diff line number Diff line change
Expand Up @@ -85,7 +85,6 @@
"renovate.json",
"samples/install-without-bom/pom.xml",
"samples/pom.xml",
"samples/snapshot/pom.xml",
"samples/snippets/pom.xml"
"samples/snapshot/pom.xml"
]
}
2 changes: 1 addition & 1 deletion versions.txt
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
# Format:
# module:released-version:current-version

google-cloud-spanner-jdbc:2.11.9:2.11.10-SNAPSHOT
google-cloud-spanner-jdbc:2.12.0:2.12.1-SNAPSHOT

0 comments on commit 889b310

Please sign in to comment.