diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index e6bb38b..9663666 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -30,7 +30,7 @@ jobs: strategy: fail-fast: false matrix: - java: [8] + java: [8, 17, 21] steps: - name: Checkout source uses: actions/checkout@v4 diff --git a/pom.xml b/pom.xml index 0d5329c..021279d 100644 --- a/pom.xml +++ b/pom.xml @@ -305,6 +305,7 @@ [1.8,) + 1.18.30 -Xdoclint:none diff --git a/src/main/java/com/sleepycat/berkeley/spring/boot/BerkeleyTemplate.java b/src/main/java/com/sleepycat/berkeley/spring/boot/BerkeleyTemplate.java index fbbb017..f51f257 100644 --- a/src/main/java/com/sleepycat/berkeley/spring/boot/BerkeleyTemplate.java +++ b/src/main/java/com/sleepycat/berkeley/spring/boot/BerkeleyTemplate.java @@ -161,12 +161,34 @@ public void otherMethod(){ List list = myDbEnvironment.getDatabaseNames();//取得当前环境下数据库名称列表 System.out.println(list); - // JE requires the handle to be closed before truncation. Reopen it so - // this template remains usable after clearing the records. - com.sleepycat.je.DatabaseConfig config = myDatabase.getConfig(); - myDatabase.close(); - long deleteNum = env.truncateDatabase(null, databaseName, true); - myDatabase = env.openDatabase(null, databaseName, config); + // Delete in a transaction while keeping the shared Database handle open. + Transaction txn = env.beginTransaction(null, null); + Cursor cursor = null; + long deleteNum = 0; + boolean committed = false; + try { + cursor = myDatabase.openCursor(txn, null); + DatabaseEntry key = new DatabaseEntry(); + DatabaseEntry value = new DatabaseEntry(); + while (cursor.getNext(key, value, LockMode.DEFAULT) == OperationStatus.SUCCESS) { + cursor.delete(); + deleteNum++; + } + cursor.close(); + cursor = null; + txn.commit(); + committed = true; + } finally { + try { + if (cursor != null) { + cursor.close(); + } + } finally { + if (!committed) { + txn.abort(); + } + } + } System.out.println(deleteNum); diff --git a/src/test/java/com/sleepycat/berkeley/spring/boot/BerkeleyTest.java b/src/test/java/com/sleepycat/berkeley/spring/boot/BerkeleyTest.java index 3d393ba..88cf509 100644 --- a/src/test/java/com/sleepycat/berkeley/spring/boot/BerkeleyTest.java +++ b/src/test/java/com/sleepycat/berkeley/spring/boot/BerkeleyTest.java @@ -29,6 +29,7 @@ import java.util.Arrays; import static org.junit.jupiter.api.Assertions.*; +import static org.mockito.Mockito.*; class BerkeleyTest { @TempDir Path home; @@ -40,6 +41,7 @@ class BerkeleyTest { void openDatabase() { EnvironmentConfig envConfig = new EnvironmentConfig(); envConfig.setAllowCreate(true); + envConfig.setConfigParam("je.freeDisk", "0"); envConfig.setTransactional(true); environment = new Environment(home.toFile(), envConfig); DatabaseConfig dbConfig = new DatabaseConfig(); @@ -80,12 +82,27 @@ void storesPrimitiveValues() { @Test - void truncatesAndReopensTheDatabase() { + void clearsAllRecordsWithoutReplacingSharedHandle() { template.writeToDatabase("keep", "before", true); + template.writeToDatabase("second", "before", true); template.otherMethod(); - database = template.getDatabase(); + assertSame(database, template.getDatabase()); assertEquals("", template.readFromDatabase("keep")); + assertEquals("", template.readFromDatabase("second")); template.writeToDatabase("after", "value", true); assertEquals("value", template.readFromDatabase("after")); } + @Test + void failedClearLeavesTheSharedHandleUntouched() { + Database failing = mock(Database.class); + when(failing.getDatabaseName()).thenReturn("items"); + when(failing.getEnvironment()).thenReturn(environment); + when(failing.openCursor(any(com.sleepycat.je.Transaction.class), isNull())).thenThrow(new IllegalStateException("cursor unavailable")); + template.setDatabase(failing); + assertThrows(IllegalStateException.class, () -> template.otherMethod()); + assertSame(failing, template.getDatabase()); + template.setDatabase(database); + template.writeToDatabase("after-failure", "valid", true); + assertEquals("valid", template.readFromDatabase("after-failure")); + } }