diff --git a/repository-ydb-v2/src/main/java/tech/ydb/yoj/repository/ydb/YdbRepositoryTransaction.java b/repository-ydb-v2/src/main/java/tech/ydb/yoj/repository/ydb/YdbRepositoryTransaction.java index ef4ef52e..95e4d535 100644 --- a/repository-ydb-v2/src/main/java/tech/ydb/yoj/repository/ydb/YdbRepositoryTransaction.java +++ b/repository-ydb-v2/src/main/java/tech/ydb/yoj/repository/ydb/YdbRepositoryTransaction.java @@ -233,6 +233,10 @@ private TxControl getTxControl() { case ONLINE_CONSISTENT_READ_ONLY -> TxControl.onlineRo().setAllowInconsistentReads(false); case ONLINE_INCONSISTENT_READ_ONLY -> TxControl.onlineRo().setAllowInconsistentReads(true); case STALE_CONSISTENT_READ_ONLY -> TxControl.staleRo(); + case SNAPSHOT -> { + TxControl txControl = (txId != null ? TxControl.id(txId) : TxControl.snapshotRo()); + yield txControl.setCommitTx(false); + } }; } diff --git a/repository-ydb-v2/src/test/java/tech/ydb/yoj/repository/ydb/YdbRepositoryIntegrationTest.java b/repository-ydb-v2/src/test/java/tech/ydb/yoj/repository/ydb/YdbRepositoryIntegrationTest.java index db7baaa4..0b5acded 100644 --- a/repository-ydb-v2/src/test/java/tech/ydb/yoj/repository/ydb/YdbRepositoryIntegrationTest.java +++ b/repository-ydb-v2/src/test/java/tech/ydb/yoj/repository/ydb/YdbRepositoryIntegrationTest.java @@ -33,6 +33,7 @@ import tech.ydb.yoj.databind.schema.Column; import tech.ydb.yoj.databind.schema.ObjectSchema; import tech.ydb.yoj.repository.db.EntitySchema; +import tech.ydb.yoj.repository.db.IsolationLevel; import tech.ydb.yoj.repository.db.Repository; import tech.ydb.yoj.repository.db.RepositoryTransaction; import tech.ydb.yoj.repository.db.Tx; @@ -304,6 +305,30 @@ public void transactionLevel() { checkSession(sessionManager, firstSession); } + @Test + public void snapshotTransactionLevel() { + Project expected1 = new Project(new Project.Id("SP1"), "snapshot1"); + Project expected2 = new Project(new Project.Id("SP2"), "snapshot2"); + + db.tx(() -> db.projects().save(expected1)); + db.tx(() -> db.projects().save(expected2)); + + Project actual1 = db.tx(() -> db.projects().find(expected1.getId())); + assertThat(actual1).isEqualTo(expected1); + Project actual2 = db.readOnly().run(() -> db.projects().find(expected2.getId())); + assertThat(actual2).isEqualTo(expected2); + + db.readOnly() + .withStatementIsolationLevel(IsolationLevel.SNAPSHOT) + .run(() -> { + Project actualSnapshot1 = db.projects().find(expected1.getId()); + assertThat(actualSnapshot1).isEqualTo(expected1); + + Project actualSnapshot2 = db.projects().find(expected2.getId()); + assertThat(actualSnapshot2).isEqualTo(expected2); + }); + } + @SneakyThrows @Test public void truncated() { diff --git a/repository/src/main/java/tech/ydb/yoj/repository/db/IsolationLevel.java b/repository/src/main/java/tech/ydb/yoj/repository/db/IsolationLevel.java index 8806e485..b16508e7 100644 --- a/repository/src/main/java/tech/ydb/yoj/repository/db/IsolationLevel.java +++ b/repository/src/main/java/tech/ydb/yoj/repository/db/IsolationLevel.java @@ -32,7 +32,14 @@ public enum IsolationLevel { * An almost recent consistent state of the database. Read only. * This level is faster then {@code ONLINE_CONSISTENT_READ_ONLY}, but may return stale data. */ - STALE_CONSISTENT_READ_ONLY("SC"); + STALE_CONSISTENT_READ_ONLY("SC"), + + /** + * All the read operations within a transaction access the database snapshot. Read only. + * All the data reads are consistent. The snapshot is taken when the transaction begins, + * meaning the transaction sees all changes committed before it began. + */ + SNAPSHOT("SP"); @Getter private final String txIdSuffix;