{"id":13721370,"url":"https://github.com/GoogleCloudPlatform/cloud-spanner-r2dbc","last_synced_at":"2025-05-07T13:32:28.549Z","repository":{"id":37848865,"uuid":"182842409","full_name":"GoogleCloudPlatform/cloud-spanner-r2dbc","owner":"GoogleCloudPlatform","description":"R2DBC driver for Google Cloud Spanner","archived":false,"fork":false,"pushed_at":"2024-10-22T11:55:11.000Z","size":1246,"stargazers_count":57,"open_issues_count":35,"forks_count":29,"subscribers_count":29,"default_branch":"main","last_synced_at":"2024-10-29T18:36:11.956Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":"","language":"Java","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"apache-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/GoogleCloudPlatform.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":"CONTRIBUTING.adoc","funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2019-04-22T18:14:34.000Z","updated_at":"2024-08-12T18:13:47.000Z","dependencies_parsed_at":"2024-05-01T13:14:15.333Z","dependency_job_id":"cccf015d-cc21-4b65-8740-ee6da695e154","html_url":"https://github.com/GoogleCloudPlatform/cloud-spanner-r2dbc","commit_stats":null,"previous_names":[],"tags_count":11,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/GoogleCloudPlatform%2Fcloud-spanner-r2dbc","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/GoogleCloudPlatform%2Fcloud-spanner-r2dbc/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/GoogleCloudPlatform%2Fcloud-spanner-r2dbc/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/GoogleCloudPlatform%2Fcloud-spanner-r2dbc/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/GoogleCloudPlatform","download_url":"https://codeload.github.com/GoogleCloudPlatform/cloud-spanner-r2dbc/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":224246083,"owners_count":17279648,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2024-08-03T01:01:16.172Z","updated_at":"2024-11-14T10:31:25.783Z","avatar_url":"https://github.com/GoogleCloudPlatform.png","language":"Java","readme":"# Cloud Spanner R2DBC Driver\n\nThis project contains:\n* An implementation of Java Reactive Relational Database Connectivity SPI [R2DBC](https://r2dbc.io/) for [Cloud Spanner](https://cloud.google.com/spanner/) based on the Cloud Spanner [client library](https://github.com/googleapis/java-spanner).\n* A [Spring Data R2DBC dialect for Cloud Spanner](https://github.com/GoogleCloudPlatform/cloud-spanner-r2dbc/tree/main/cloud-spanner-spring-data-r2dbc).\n* [Sample applications](https://github.com/GoogleCloudPlatform/cloud-spanner-r2dbc/tree/main/cloud-spanner-r2dbc-samples) to help you get started.\n\n## Setup Instructions\n\nThe sections below describe how to setup and begin using the Cloud Spanner R2DBC driver.\n\nAn overview of the setup is as follows:\n\n1. Add the Cloud Spanner R2DBC driver dependency to your build configuration.\n2. Configure the driver credentials/authentication for your Google Cloud Platform project to access\n    Cloud Spanner.\n3. Instantiate the R2DBC `ConnectionFactory` in Java code to build Connections and run queries.\n\nDetails about each step is provided below.\n\n### Project Dependency Setup\n\nThe easiest way to start using the driver is to add the driver dependency through Maven or Gradle.\n\n**Maven Coordinates**\n\n```xml\n\u003cdependency\u003e\n  \u003cgroupId\u003ecom.google.cloud\u003c/groupId\u003e\n  \u003cartifactId\u003ecloud-spanner-r2dbc\u003c/artifactId\u003e\n  \u003cversion\u003e1.2.0\u003c/version\u003e\n\u003c/dependency\u003e\n```\n\n**Gradle Coordinates**\n\n```\ndependencies {\n  compile group: 'com.google.cloud', name: 'cloud-spanner-r2dbc', version: '1.2.0'\n}\n```\n\n### Usage\n\nAfter setting up the dependency and [authentication](#authentication), you can begin directly using the driver.\n\nThe rest of this documentation will show examples of directly using the driver.\nIn a real application, you should use one of R2DBC's user-friendly [client APIs](https://r2dbc.io/clients/) instead.\n\nTo start using Cloud Spanner R2DBC driver, configure the R2DBC connection factory either programmatically, as shown below, or with a URL.\n\n```\nimport static com.google.cloud.spanner.r2dbc.SpannerConnectionFactoryProvider.PROJECT;\nimport static com.google.cloud.spanner.r2dbc.SpannerConnectionFactoryProvider.INSTANCE;\n\nConnectionFactory connectionFactory =\n    ConnectionFactories.get(ConnectionFactoryOptions.builder()\n        .option(DRIVER, \"cloudspanner\")\n        .option(PROJECT, \"your-gcp-project-id\")\n        .option(INSTANCE, \"your-spanner-instance\")\n        .option(DATABASE, \"your-database-name\")\n        .build());\n        \n// The R2DBC connection may now be created.\nPublisher\u003c? extends Connection\u003e connectionPublisher = connectionFactory.create();\n```\n\n### Connection URLs\n\nYou may specify the coordinates of your Cloud Spanner database using the `ConnectionFactories.get(String)` SPI method instead of specifying the `project`, `instance`, and `database` properties individually.\n\nA Cloud Spanner R2DBC URL is constructed in the following format:\n\n```\nr2dbc:cloudspanner://spanner.googleapis.com:443/projects/${PROJECT_NAME}/instances/${INSTANCE_NAME}/databases/${DB_NAME}\n```\n\n- `${PROJECT_NAME}`: Replace with the name of your Google Cloud Platform Project ID.\n- `${INSTANCE_NAME}`: Replace with the name of your Spanner Instance.\n- `${DB_NAME}`: Replace with the name of your Spanner database.\n\n## Cleaning Up\n\nClient library-based `ConnectionFactory` must be closed as part of application shutdown process to ensure all server-side Cloud Spanner sessions are cleaned up.\n\n```\nMono.from(((Closeable) connectionFactory).close()).subscribe();\n```\n\n### Authentication\n\nThe driver allows the following options for authentication:\n\n* a `String` property `credentials` containing the local file location of the JSON credentials file.\n* a `String` OAuth token provided as `oauthToken`.\n* a `Credentials` object provided as `google_credentials`. This will only work with programmatically constructed `ConnectionFactoryOptions`.\n    Example:\n\n    ```java\n    import static com.google.cloud.spanner.r2dbc.SpannerConnectionFactoryProvider.GOOGLE_CREDENTIALS;\n    \n    String pathToCredentialsKeyFile = ...;\n    \n    GoogleCredentials creds = GoogleCredentials.fromStream(new FileInputStream(credentialsLocation));\n    ConnectionFactoryOptions options =\n        ConnectionFactoryOptions.builder()\n            .option(GOOGLE_CREDENTIALS, creds)\n            .option(..) // Other options here\n            .build();\n    ```\n\nIn the absence of explicit authentication options, Application Default Credentials will be automatically inferred from the environment in which the application is running, unless the connection is in plain-text, indicating the use of Cloud Spanner emulator.\nFor more information, see the [Google Cloud Platform Authentication documentation](https://cloud.google.com/docs/authentication/production#automatically)\n\n\n#### Using Google Cloud SDK\n\nGoogle Cloud SDK is a command line interface for Google Cloud Platform products and services.\nThis is a convenient way of setting up authentication during local development.\n\nIf you are using the SDK, the driver can automatically infer your account credentials from your SDK configuration.\n\nInstructions:\n\n1. Install the [Google Cloud SDK](https://cloud.google.com/sdk/) for command line and follow the [Cloud SDK quickstart](https://cloud.google.com/sdk/docs/quickstarts) for your operating system.\n    \n2. Once setup, run `gcloud auth application-default login` and login with your Google account credentials. \n\nAfter completing the SDK configuration, the Cloud Spanner R2DBC driver will automatically pick up your credentials. \n\n#### Using a Service Account\n\nA [Google Service Account](https://cloud.google.com/iam/docs/understanding-service-accounts) is a special type of Google Account intended to represent a non-human user that needs to authenticate and be authorized to access your Google Cloud resources.\nEach service account has an account key JSON file that you can use to provide credentials to your application.\n\nYou can learn how to create a service account and authenticate your application by following\n[these instructions](https://cloud.google.com/docs/authentication/production#obtaining_and_providing_service_account_credentials_manually).\n\n\n## Supported connection options\n\nAll connection options of primitive and String type can be passed through the connection URL in the `?key1=value1\u0026key2=value2` format.\nObject-typed options can only be passed in programmatically.\n\n|Property name            |Type                              |Allowed in URL connection |Default |Comments|\n|-------------------------|-------|--------------------------|--------|--------|\n|`credentials`            |String |Yes                       |null    |The location of the credentials file to use for this connection\n|`oauthToken`             |String |Yes                       |null    |A valid pre-existing OAuth token to use for authentication\n|`google_credentials`     |com.google.auth.oauth2.OAuth2Credentials|No|null|A pre-authenticated authentication object that can only be supplied with programmatic connection options\n|`usePlainText`           |boolean|Yes                       |false   |Turns off SSL and credentials use (only valid when using Cloud Spanner emulator)\n|`optimizerVersion`       |String |Yes                       |null    |Determines version of Cloud Spanner https://cloud.google.com/spanner/docs/query-optimizer/query-optimizer-versions[optimizer] to use in queries\n|`autocommit`             |boolean|Yes                       |true    |Whether new connections are created in autocommit mode\n|`readonly`               |boolean|Yes                       |false   |Whether new connections start with a read-only transaction\n\n## Mapping of Data Types\n\nCloud Spanner R2DBC Driver supports the following types:\n\n\n| Spanner Type   | Java type           |\n|----------------|---------------------|\n|`BOOL`          |`java.lang.Boolean`  |\n|`BYTES`         |`java.nio.ByteBuffer`|\n|`DATE`          |`com.google.cloud.Date`|\n|`FLOAT64`       |`java.lang.Double`   |\n|`INT64`         |`java.lang.Long`     |\n|`INT64`         |`java.lang.Integer`  |\n|`STRING`        |`java.lang.String`   |\n|`JSON`          |`com.google.cloud.spanner.r2dbc.v2.JsonWrapper`   |\n|`TIMESTAMP`     |`com.google.cloud.Timestamp` |\n|`ARRAY`         |Arrays or `Iterable` collections with hint. `ARRAY\u003cJSON\u003e` is not supported.|\n\nNull values mapping is supported in both directions.\nSee [Cloud Spanner documentation](https://cloud.google.com/spanner/docs/data-types) to learn more about Spanner types.\n\n### TIMESTAMP and DATE Mapping\n\n`TIMESTAMP` and `DATE` Spanner column types are supported via `com.google.cloud.Timestamp` and `com.google.cloud.Date` classes.\n\nCustom converters need to be implemented and registered if you want to use other Time/Date classes.\nFor examples, please refer to the following integration test: [SpannerR2dbcDialectDateTimeBindingIntegrationTest.java](https://github.com/GoogleCloudPlatform/cloud-spanner-r2dbc/blob/main/cloud-spanner-spring-data-r2dbc/src/test/java/com/google/cloud/spanner/r2dbc/springdata/it/SpannerR2dbcDialectDateTimeBindingIntegrationTest.java)\n\n### JSON Mapping\n\n`JSON` Spanner type is supported through `JsonWrapper.class`. This is a wrapper class around String representation of the Json value. Below are the basic usages wrapping and un-wrapping string: \n```java\n  // Create jsonWrapper object from String\n  JsonWrapper jsonWrapper = JsonWrapper.of(jsonString);\n  JsonWrapper jsonWrapper = new JsonWrapper(jsonString);\n\n  // Get underlying string from jsonWrapper object\n  String jsonString = jsonWrapper.toString();\n```\n\nIf using Spring Data, default converters to/from `Map` are ready to use out-of-box for key or value type of `String`, `Boolean` and `Double`. Custom converters can be used to allow Json conversion directly to/from collections or user-defined types. Examples of using `Map` and custom class `Review` for Json field are provided in the [Spring Data sample application](https://github.com/GoogleCloudPlatform/cloud-spanner-r2dbc/tree/main/cloud-spanner-r2dbc-samples/cloud-spanner-spring-data-r2dbc-sample)\n\n### Array Mapping\n\nCloud Spanner arrays can be mapped to/from either primitive Java arrays or `Iterable` collections of wrapper types. For example, a column of type `ARRAY\u003cINT64\u003e` can be represented as `long[]` or `List\u003cLong\u003e`.\n\nHowever, binding `Iterable` parameters requires a `SpannerType` hint for the specific `com.google.cloud.spanner.Type` to use.\n\n```\n  List value = ...;\n  SpannerType typeHint = SpannerType.of( Type.array(Type.string()) );\n  statement.bind(\"columnName\", Parameters.in(typeHint, value));\n```\nThis is not a concern when using Spring Data, as collections will automatically be converted to typed arrays by the framework.\n\nNOTE: Using `long` and `double` arrays is more efficient than using `int` and `float`, as the latter need to get converted for every element.\n\n## Connections\n\nThe R2DBC Cloud Spanner `Connection` object is a lightweight wrapper around the shared Cloud Spanner client library object combined with transaction state.\n\nThe client library takes care of reconnecting lapsed Cloud Spanner sessions.\n\nIf you'd like to ensure the current connection stays connected, you may keep a connection active by calling `validate(ValidationDepth.REMOTE)` on the `Connection` object and subscribing to the returned `Publisher`.\nRemote validation performs an inexpensive SQL query `SELECT 1` against the database. \n\n## Transactions\n\nIn Cloud Spanner, a transaction represents a set of read and write statements that execute atomically at a single logical point in time across columns, rows, and tables in a database.\n\nNote: Transactional save points are unsupported in Cloud Spanner and are unimplemented by this R2DBC driver.\n\n### Transaction Types\n\nSpanner offers [three transaction types](https://cloud.google.com/spanner/docs/transactions) in which to execute SQL statements:\n\n- Read-Write: Supports reading and writing data into Cloud Spanner.\n    When you begin a transaction in the `Connection` object using `connection.beginTransaction()`, a read-write transaction is started by default, unless the connection was created or altered to run in read-only mode.\n    \n    ```java\n    Mono.from(connectionFactory.create())\n                .flatMapMany(c -\u003e Flux.concat(\n                    c.beginTransaction(),\n                    ...\n                    c.commitTransaction(),\n                    c.close()))\n    ```\n\n- Read-Only: Provides guaranteed consistency across multiple reads but does not allow writing data.\n    Read-only transactions, including stale transactions, can be used by downcasting the `Connection` object to `com.google.cloud.spanner.r2dbc.api.SpannerConnection` and calling `beginReadonlyTransaction()` on it.\n    Invoking `beginReadonlyTransaction()` without parameters will begin a new strongly consistent readonly transaction, as does creating a new connection from a `ConnectionFactory` in read-only mode (`readonly=true`).\n    \n    To customize staleness, pass in a `TimestampBound` parameter.\n    See the [TransactionOptions documentation](https://cloud.google.com/spanner/docs/reference/rpc/google.spanner.v1#google.spanner.v1.TransactionOptions) for more information about all of the transaction type settings that are available.\n\n    ```java\n    Mono.from(connectionFactory.create())\n                .flatMapMany(c -\u003e\n                    Flux.concat(\n                              ((SpannerConnection) conn).beginReadonlyTransaction(TimestampBound.ofExactStaleness(1, TimeUnit.SECONDS)),\n                                ...\n                              conn.commitTransaction(),\n                        )\n    ```\n    NOTE: Readonly transactions must be closed by calling `commit()` before starting a new read-write or a read-only transaction.\n\n\n- Partitioned DML: A transaction designed for bulk updates and deletes with certain restrictions.\n    See the [Partitioned DML documentation](https://cloud.google.com/spanner/docs/dml-partitioned) for more information.\n    This driver does not support Partitioned DML transactions at the time.\n\n\n### Nesting transactions\nCloud Spanner does not support nested transactions, so each transaction must be either committed or rolled back.\nFor readonly transactions, either committing or rolling back will result in closing of the readonly transaction.\n\n\n### Autocommit Mode\n\nThe Spanner R2DBC driver can be used in autocommit mode in which statements are executed independently outside of a transaction.\n\nYou may immediately call `connection.createStatement(sql)` and begin executing SQL statements.\nEach statement will be executed as an independent unit of work.\n\n- DML statements are executed in a stand-alone read-write transaction.\n- Read queries are executed in a strongly consistent, read-only temporary transaction.\n\n## Statements \n\nR2DBC statement objects are used to run statements on your Cloud Spanner database. \nThe table below describes whether parameter bindings are available for each statement type.\n\n| Statement Type | Allows Parameter Bindings |\n|----------------|---------------------------|\n| SELECT Queries | Yes                       | \n| DML Statements | Yes                       |\n| DDL Statements | No                        |\n\n### Binding Query Parameters\n\nCloud Spanner R2DBC statements support *named* parameter binding using Cloud Spanner's [parameter syntax](https://cloud.google.com/spanner/docs/sql-best-practices).\nParameter bindings by numeric indices are not supported.\n\nSQL and DML statements can be constructed with parameters:\n\n```java\nmySpannerConnection.createStatement(\n  \"INSERT BOOKS (ID, TITLE) VALUES (@id, @title)\")\n    .bind(\"id\", \"book-id-1\")\n    .bind(\"title\", \"Book One\")\n    .add()\n    .bind(\"id\", \"book-id-2\")\n    .bind(\"title\", \"Book Two\")\n    .execute()\n    .flatMap(r -\u003e r.getRowsUpdated());\n``` \n\nThe parameter identifiers must be `String`. \n\nThe example above binds two sets of parameters to a single DML template. \nIt will produce a `Publisher` (implemented by a `Flux`) containing two `SpannerResult` objects for the two instances of the statement that are executed. \n\nNote that calling `execute` produces R2DBC `Result` objects, but this doesn't cause the query to be run on the database. \nYou must use the `map` or `getRowsUpdated` methods of the results to complete the underlying queries.\n\n\n## Backpressure\n\nBackpressure on SQL SELECT queries is supported out of the box.\nTake care to always ultimately exhaust or cancel the query result `Publisher`, since not doing so may lead to objects not being deallocated properly.\n\n## Exception Handling\n\nThe Cloud Spanner R2DBC propagates all exceptions down to the user.\nAll exceptions thrown are wrapped by and propagated through two exception classes:\n\n- `R2dbcTransientException`: Errors caused by network problems or causes outside of the user's control.\n    The operations that fail due to these errors can be retried.\n    \n- `R2dbcNonTransientException`: Errors caused by invalid operations or user error.\n    These include SQL syntax errors, invalid requests, performing invalid operations on the Spanner driver, etc.\n    These errors should not be retried.\n    \nThe user may leverage reactive methods to retry operations which throw `R2dbcTransientException`.\n\nExample using Project Reactor's [`Retry` utilities](https://projectreactor.io/docs/extra/snapshot/api/overview-summary.html):\n\n```java\n// This describes a retry strategy which only attempts a retry if the exception class\n// matches R2dbcTransientException.class\nRetry retry =\n    Retry.anyOf(R2dbcTransientException.class)\n        .randomBackoff(Duration.ofMillis(100), Duration.ofSeconds(60))\n        .retryMax(5);\n\nMono.from(connection\n    .createStatement(\"Select * from table\")\n    .execute())\n    .retryWhen(retry); // This retries the subscription using the retry strategy.\n```\n\n## Batches\nA batch contains multiple statements that are executed in one remote call for performance reasons.\nOnly DML statements are supported.\n\nThe call to `execute()` produces a publisher that will publish results.\nThe statements are executed in sequential order.\nFor every successfully executed statement, there will be a result that contains a number of updated rows.\n \n```java\nFlux.from(connection.createBatch()\n    .add(\"INSERT INTO books VALUES('Mark Twain', 'The Adventures of Tom Sawyer'\")\n    .add(\"INSERT INTO books VALUES('Mark Twain', 'Adventures of Huckleberry Finn'\")\n    .execute())\n    .flatMap(r -\u003e r.getRowsUpdated());\n```\n\n## Using Connection Pool\n\nClient Spanner client library maintains its own low-level connection pool, making use of [r2dbc pool](https://github.com/r2dbc/r2dbc-pool) unnecessary.\nWhen R2DBC connections are closed, the underlying Client Spanner connection is reused internally.\n","funding_links":[],"categories":["Libraries and ORM","\u003ca name=\"Java\"\u003e\u003c/a\u003eJava"],"sub_categories":["Drivers"],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2FGoogleCloudPlatform%2Fcloud-spanner-r2dbc","html_url":"https://awesome.ecosyste.ms/projects/github.com%2FGoogleCloudPlatform%2Fcloud-spanner-r2dbc","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2FGoogleCloudPlatform%2Fcloud-spanner-r2dbc/lists"}