Skip to content
This repository was archived by the owner on Apr 7, 2026. It is now read-only.
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 12 additions & 0 deletions google-cloud-spanner/clirr-ignored-differences.xml
Original file line number Diff line number Diff line change
Expand Up @@ -850,6 +850,18 @@
<className>com/google/cloud/spanner/connection/Connection</className>
<method>java.lang.String getDefaultSequenceKind()</method>
</difference>

<!-- Default isolation level -->
<difference>
<differenceType>7012</differenceType>
<className>com/google/cloud/spanner/connection/Connection</className>
<method>void setDefaultIsolationLevel(com.google.spanner.v1.TransactionOptions$IsolationLevel)</method>
</difference>
<difference>
<differenceType>7012</differenceType>
<className>com/google/cloud/spanner/connection/Connection</className>
<method>com.google.spanner.v1.TransactionOptions$IsolationLevel getDefaultIsolationLevel()</method>
</difference>

<!-- Removed ConnectionOptions$ConnectionProperty in favor of the more generic ConnectionProperty class. -->
<difference>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@
import com.google.common.base.Preconditions;
import com.google.common.base.Strings;
import com.google.spanner.v1.DirectedReadOptions;
import com.google.spanner.v1.TransactionOptions;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
import java.time.Duration;
Expand Down Expand Up @@ -382,6 +383,33 @@ public DirectedReadOptions convert(String value) {
}
}

/**
* Converter for converting strings to {@link
* com.google.spanner.v1.TransactionOptions.IsolationLevel} values.
*/
static class IsolationLevelConverter
implements ClientSideStatementValueConverter<TransactionOptions.IsolationLevel> {
static final IsolationLevelConverter INSTANCE = new IsolationLevelConverter();

private final CaseInsensitiveEnumMap<TransactionOptions.IsolationLevel> values =
new CaseInsensitiveEnumMap<>(TransactionOptions.IsolationLevel.class);

private IsolationLevelConverter() {}

/** Constructor needed for reflection. */
public IsolationLevelConverter(String allowedValues) {}

@Override
public Class<TransactionOptions.IsolationLevel> getParameterClass() {
return TransactionOptions.IsolationLevel.class;
}

@Override
public TransactionOptions.IsolationLevel convert(String value) {
return values.get(value);
}
}

/** Converter for converting strings to {@link AutocommitDmlMode} values. */
static class AutocommitDmlModeConverter
implements ClientSideStatementValueConverter<AutocommitDmlMode> {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@
import com.google.spanner.v1.DirectedReadOptions;
import com.google.spanner.v1.ExecuteBatchDmlRequest;
import com.google.spanner.v1.ResultSetStats;
import com.google.spanner.v1.TransactionOptions.IsolationLevel;
import java.time.Duration;
import java.util.Iterator;
import java.util.Set;
Expand Down Expand Up @@ -219,6 +220,12 @@ public interface Connection extends AutoCloseable {
/** @return <code>true</code> if this connection is in read-only mode */
boolean isReadOnly();

/** Sets the default isolation level for read/write transactions for this connection. */
void setDefaultIsolationLevel(IsolationLevel isolationLevel);

/** Returns the default isolation level for read/write transactions for this connection. */
IsolationLevel getDefaultIsolationLevel();

/**
* Sets the duration the connection should wait before automatically aborting the execution of a
* statement. The default is no timeout. Statement timeouts are applied all types of statements,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@
import static com.google.cloud.spanner.connection.ConnectionProperties.AUTO_PARTITION_MODE;
import static com.google.cloud.spanner.connection.ConnectionProperties.DATA_BOOST_ENABLED;
import static com.google.cloud.spanner.connection.ConnectionProperties.DDL_IN_TRANSACTION_MODE;
import static com.google.cloud.spanner.connection.ConnectionProperties.DEFAULT_ISOLATION_LEVEL;
import static com.google.cloud.spanner.connection.ConnectionProperties.DEFAULT_SEQUENCE_KIND;
import static com.google.cloud.spanner.connection.ConnectionProperties.DELAY_TRANSACTION_START_UNTIL_FIRST_WRITE;
import static com.google.cloud.spanner.connection.ConnectionProperties.DIRECTED_READ;
Expand Down Expand Up @@ -90,6 +91,7 @@
import com.google.spanner.v1.DirectedReadOptions;
import com.google.spanner.v1.ExecuteSqlRequest.QueryOptions;
import com.google.spanner.v1.ResultSetStats;
import com.google.spanner.v1.TransactionOptions.IsolationLevel;
import io.opentelemetry.api.OpenTelemetry;
import io.opentelemetry.api.common.Attributes;
import io.opentelemetry.api.common.AttributesBuilder;
Expand Down Expand Up @@ -478,6 +480,7 @@ private void reset(Context context, boolean inTransaction) {
this.connectionState.resetValue(RETRY_ABORTS_INTERNALLY, context, inTransaction);
this.connectionState.resetValue(AUTOCOMMIT, context, inTransaction);
this.connectionState.resetValue(READONLY, context, inTransaction);
this.connectionState.resetValue(DEFAULT_ISOLATION_LEVEL, context, inTransaction);
this.connectionState.resetValue(READ_ONLY_STALENESS, context, inTransaction);
this.connectionState.resetValue(OPTIMIZER_VERSION, context, inTransaction);
this.connectionState.resetValue(OPTIMIZER_STATISTICS_PACKAGE, context, inTransaction);
Expand Down Expand Up @@ -635,6 +638,24 @@ public boolean isReadOnly() {
return getConnectionPropertyValue(READONLY);
}

@Override
public void setDefaultIsolationLevel(IsolationLevel isolationLevel) {
ConnectionPreconditions.checkState(!isClosed(), CLOSED_ERROR_MSG);
ConnectionPreconditions.checkState(
!isBatchActive(), "Cannot default isolation level while in a batch");
ConnectionPreconditions.checkState(
!isTransactionStarted(),
"Cannot set default isolation level while a transaction is active");
setConnectionPropertyValue(DEFAULT_ISOLATION_LEVEL, isolationLevel);
clearLastTransactionAndSetDefaultTransactionOptions();
}

@Override
public IsolationLevel getDefaultIsolationLevel() {
ConnectionPreconditions.checkState(!isClosed(), CLOSED_ERROR_MSG);
return getConnectionPropertyValue(DEFAULT_ISOLATION_LEVEL);
}

private void clearLastTransactionAndSetDefaultTransactionOptions() {
setDefaultTransactionOptions();
this.currentUnitOfWork = null;
Expand Down Expand Up @@ -2196,6 +2217,7 @@ UnitOfWork createNewUnitOfWork(
.setUsesEmulator(options.usesEmulator())
.setUseAutoSavepointsForEmulator(options.useAutoSavepointsForEmulator())
.setDatabaseClient(dbClient)
.setIsolationLevel(getConnectionPropertyValue(DEFAULT_ISOLATION_LEVEL))
.setDelayTransactionStartUntilFirstWrite(
getConnectionPropertyValue(DELAY_TRANSACTION_START_UNTIL_FIRST_WRITE))
.setKeepTransactionAlive(getConnectionPropertyValue(KEEP_TRANSACTION_ALIVE))
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -112,6 +112,7 @@
import com.google.cloud.spanner.connection.ClientSideStatementValueConverters.DdlInTransactionModeConverter;
import com.google.cloud.spanner.connection.ClientSideStatementValueConverters.DialectConverter;
import com.google.cloud.spanner.connection.ClientSideStatementValueConverters.DurationConverter;
import com.google.cloud.spanner.connection.ClientSideStatementValueConverters.IsolationLevelConverter;
import com.google.cloud.spanner.connection.ClientSideStatementValueConverters.LongConverter;
import com.google.cloud.spanner.connection.ClientSideStatementValueConverters.NonNegativeIntegerConverter;
import com.google.cloud.spanner.connection.ClientSideStatementValueConverters.ReadOnlyStalenessConverter;
Expand All @@ -123,7 +124,9 @@
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableMap;
import com.google.spanner.v1.DirectedReadOptions;
import com.google.spanner.v1.TransactionOptions.IsolationLevel;
import java.time.Duration;
import java.util.Arrays;

/** Utility class that defines all known connection properties. */
public class ConnectionProperties {
Expand Down Expand Up @@ -397,13 +400,28 @@ public class ConnectionProperties {
BOOLEANS,
BooleanConverter.INSTANCE,
Context.USER);
static final ConnectionProperty<IsolationLevel> DEFAULT_ISOLATION_LEVEL =
create(
"default_isolation_level",
"The transaction isolation level that is used by default for read/write transactions. "
+ "The default is isolation_level_unspecified, which means that the connection will use the "
+ "default isolation level of the database that it is connected to.",
IsolationLevel.ISOLATION_LEVEL_UNSPECIFIED,
new IsolationLevel[] {
IsolationLevel.ISOLATION_LEVEL_UNSPECIFIED,
IsolationLevel.SERIALIZABLE,
IsolationLevel.REPEATABLE_READ
},
IsolationLevelConverter.INSTANCE,
Context.USER);
static final ConnectionProperty<AutocommitDmlMode> AUTOCOMMIT_DML_MODE =
create(
"autocommit_dml_mode",
"Determines the transaction type that is used to execute "
+ "DML statements when the connection is in auto-commit mode.",
AutocommitDmlMode.TRANSACTIONAL,
AutocommitDmlMode.values(),
// Add 'null' as a valid value.
Arrays.copyOf(AutocommitDmlMode.values(), AutocommitDmlMode.values().length + 1),
AutocommitDmlModeConverter.INSTANCE,
Context.USER);
static final ConnectionProperty<Boolean> RETRY_ABORTS_INTERNALLY =
Expand Down Expand Up @@ -519,7 +537,8 @@ public class ConnectionProperties {
RPC_PRIORITY_NAME,
"Sets the priority for all RPC invocations from this connection (HIGH/MEDIUM/LOW). The default is HIGH.",
DEFAULT_RPC_PRIORITY,
RpcPriority.values(),
// Add 'null' as a valid value.
Arrays.copyOf(RpcPriority.values(), RpcPriority.values().length + 1),
RpcPriorityConverter.INSTANCE,
Context.USER);
static final ConnectionProperty<SavepointSupport> SAVEPOINT_SUPPORT =
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,10 +27,12 @@
import com.google.cloud.spanner.connection.ConnectionProperty.Context;
import com.google.common.annotations.VisibleForTesting;
import com.google.common.base.Suppliers;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Objects;
import java.util.function.Supplier;
import javax.annotation.Nullable;

Expand Down Expand Up @@ -233,6 +235,7 @@ private <T> void internalSetValue(
T value,
Map<String, ConnectionPropertyValue<?>> currentProperties,
Context context) {
checkValidValue(property, value);
ConnectionPropertyValue<T> newValue = cast(currentProperties.get(property