From ee6c65b77fd96cddcca7449dde4513edb8b3b5e3 Mon Sep 17 00:00:00 2001
From: loong10k <20489781+loong10k@users.noreply.github.com>
Date: Sat, 31 Oct 2026 22:03:44 +0800
Subject: [PATCH] test: verify legacy Berkeley JE behavior on JDK 8
---
.github/workflows/ci.yml | 2 +-
pom.xml | 5 +-
.../spring/boot/BerkeleyTemplate.java | 10 +-
.../berkeley/spring/boot/BerkeleyTest.java | 446 ++++--------------
4 files changed, 99 insertions(+), 364 deletions(-)
diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml
index 9663666..e6bb38b 100644
--- a/.github/workflows/ci.yml
+++ b/.github/workflows/ci.yml
@@ -30,7 +30,7 @@ jobs:
strategy:
fail-fast: false
matrix:
- java: [8, 17, 21]
+ java: [8]
steps:
- name: Checkout source
uses: actions/checkout@v4
diff --git a/pom.xml b/pom.xml
index a1a77df..0d5329c 100644
--- a/pom.xml
+++ b/pom.xml
@@ -167,14 +167,11 @@
maven-surefire-plugin
${maven-surefire-plugin.version}
-
- true
- true
once
- -Xmx1024m -XX:PermSize=256m -XX:MaxPermSize=256m -Dfile.encoding=UTF-8
+ -Xmx1024m -Dfile.encoding=UTF-8
${basedir}/target/test-classes
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 a85b252..fbbb017 100644
--- a/src/main/java/com/sleepycat/berkeley/spring/boot/BerkeleyTemplate.java
+++ b/src/main/java/com/sleepycat/berkeley/spring/boot/BerkeleyTemplate.java
@@ -161,10 +161,12 @@ public void otherMethod(){
List list = myDbEnvironment.getDatabaseNames();//取得当前环境下数据库名称列表
System.out.println(list);
- env.renameDatabase(null, databaseName, "newName");//给数据库改名
- env.removeDatabase(null, databaseName);//删除当前环境数据库
-
- long deleteNum = env.truncateDatabase(null, databaseName, true);//清空数据库中所有记录,并返回数量
+ // 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);
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 98639b8..3d393ba 100644
--- a/src/test/java/com/sleepycat/berkeley/spring/boot/BerkeleyTest.java
+++ b/src/test/java/com/sleepycat/berkeley/spring/boot/BerkeleyTest.java
@@ -1,355 +1,91 @@
-/*
- * Copyright (c) 2018, hiwepy (https://github.com/hiwepy).
- *
- * Licensed under the Apache License, Version 2.0 (the "License"); you may not
- * use this file except in compliance with the License. You may obtain a copy of
- * the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
- * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
- * License for the specific language governing permissions and limitations under
- * the License.
- */
-package com.sleepycat.berkeley.spring.boot;
-
-import java.io.File;
-import java.io.IOException;
-import java.util.List;
-
-import org.apache.commons.io.Charsets;
-import org.apache.commons.io.IOUtils;
-import org.apache.commons.lang3.builder.ToStringBuilder;
-import org.junit.After;
-import org.junit.Assert;
-import org.junit.Before;
-import org.junit.Test;
-
-import com.sleepycat.je.CursorConfig;
-import com.sleepycat.je.DatabaseException;
-import com.sleepycat.je.Environment;
-import com.sleepycat.je.EnvironmentConfig;
-import com.sleepycat.persist.EntityCursor;
-import com.sleepycat.persist.EntityIndex;
-import com.sleepycat.persist.EntityStore;
-import com.sleepycat.persist.PrimaryIndex;
-import com.sleepycat.persist.SecondaryIndex;
-import com.sleepycat.persist.StoreConfig;
-
-public class BerkeleyTest {
-
- private Environment myEnv;
- private EntityStore store;
- private PrimaryIndex inventoryBySku;
- private PrimaryIndex vendorByName;
- private SecondaryIndex inventoryByName;
-
- /* Employer accessors */
- PrimaryIndex employerById;
- SecondaryIndex employerByName;
-
- /* Person accessors */
- PrimaryIndex personBySsn;
- SecondaryIndex personByParentSsn;
- SecondaryIndex personByEmailAddresses;
- SecondaryIndex personByEmployerIds;
-
-
- private File envHome = new File(System.getProperty("user.dir") + File.separator + "bdb");
- private boolean readOnly = false;
-
- @Before
- public void prepare() {
- EnvironmentConfig myEnvConfig = new EnvironmentConfig();
- StoreConfig storeConfig = new StoreConfig();
-
- myEnvConfig.setReadOnly(readOnly);
- storeConfig.setReadOnly(readOnly);
-
- // If the environment is opened for write, then we want to be
- // able to create the environment and entity store if
- // they do not exist.
- myEnvConfig.setAllowCreate(!readOnly);
- storeConfig.setAllowCreate(!readOnly);
-
- // Open the environment and entity store
- System.out.println(envHome.getAbsolutePath());
- if (!envHome.exists()) {
- envHome.mkdir();
- }
- myEnv = new Environment(envHome, myEnvConfig);
- store = new EntityStore(myEnv, "EntityStore", storeConfig);
-
- // Primary key for Inventory classes
- inventoryBySku = store.getPrimaryIndex(String.class, Inventory.class);
- // Secondary key for Inventory classes
- // Last field in the getSecondaryIndex() method must be
- // the name of a class member; in this case, an Inventory.class
- // data member.
- inventoryByName = store.getSecondaryIndex(inventoryBySku, String.class, "itemName");
- // Primary key for Vendor class
- vendorByName = store.getPrimaryIndex(String.class, Vendor.class);
-
- employerById = store.getPrimaryIndex(Long.class, Employer.class);
- employerByName = store.getSecondaryIndex(employerById, String.class, "name");
-
- personBySsn = store.getPrimaryIndex(String.class, Person.class);
- personByParentSsn = store.getSecondaryIndex(personBySsn, String.class, "parentSsn");
- personByEmailAddresses = store.getSecondaryIndex(personBySsn, String.class, "emailAddresses");
- personByEmployerIds = store.getSecondaryIndex(personBySsn, Long.class, "employerIds");
-
- }
-
- //添加数据
- @Test
- public void putData() throws IOException {
-
- List readLines = IOUtils.readLines(this.getClass().getClassLoader().getResourceAsStream("vendors.txt"), Charsets.UTF_8);
- for (String data : readLines) {
- String[] sArray = data.split("#");
- Vendor theVendor = new Vendor();
- theVendor.setVendorName(sArray[0]);
- theVendor.setAddress(sArray[1]);
- theVendor.setCity(sArray[2]);
- theVendor.setState(sArray[3]);
- theVendor.setZipcode(sArray[4]);
- theVendor.setBusinessPhoneNumber(sArray[5]);
- theVendor.setRepName(sArray[6]);
- theVendor.setRepPhoneNumber(sArray[7]);
- // Put it in the store. Because we do not explicitly set
- // a transaction here, and because the store was opened
- // with transactional support, auto commit is used for each
- // write to the store.
- vendorByName.put(theVendor);
- }
-
- // Primary key for Inventory classes
- PrimaryIndex inventoryBySku = store.getPrimaryIndex(String.class, Inventory.class);
- List data = IOUtils.readLines(this.getClass().getClassLoader().getResourceAsStream("inventory.txt"), Charsets.UTF_8);
- for (String row : data) {
- String[] sArray = row.split("#");
- Inventory theInventory = new Inventory();
- theInventory.setItemName(sArray[0]);
- theInventory.setSku(sArray[1]);
- theInventory.setVendorPrice((new Float(sArray[2])).floatValue());
- theInventory.setVendorInventory((new Integer(sArray[3])).intValue());
- theInventory.setCategory(sArray[4]);
- theInventory.setVendor(sArray[5]);
- // Put it in the store. Note that this causes our secondary key
- // to be automatically updated for us.
- inventoryBySku.put(theInventory);
- }
- }
-
- //查询数据
- @Test
- public void getInventoryData() {
- // Use the inventory name secondary key to retrieve
- // these objects.
- EntityCursor items =
- inventoryByName.subIndex("Oranges").entities();
- try {
- for (Inventory item : items) {
- System.out.println(ToStringBuilder.reflectionToString(item));
- }
- } finally {
- items.close();
- }
- }
-
- @Test
- public void getAllInventory() {
- // Get a cursor that will walk every
- // inventory object in the store.
- EntityCursor items = inventoryBySku.entities();
-
- try {
- for (Inventory item : items) {
- System.out.println(ToStringBuilder.reflectionToString(item));
- }
- } finally {
- items.close();
- }
- }
-
- //更新:如果不开启允许重复记录的话,put就是更新
- @Test
- public void update() {
- String pk = "apple-for-update";
- Inventory theInventory = new Inventory();
- theInventory.setItemName("Apples");
- theInventory.setSku(pk);
- theInventory.setVendorPrice(1.20f);
- theInventory.setVendorInventory(728);
- theInventory.setCategory("fruits");
- theInventory.setVendor("Off the Vine");
-
- inventoryBySku.put(theInventory);
-
- Inventory inventory = inventoryBySku.get(pk);
- System.out.println(ToStringBuilder.reflectionToString(inventory));
-
- inventory.setVendor("vendor update");
- inventoryBySku.put(inventory);
-
- System.out.println(ToStringBuilder.reflectionToString(inventoryBySku.get(pk)));
- }
-
- //删除
- @Test
- public void delete() {
-
- String pk = "apple-for-update";
- Inventory theInventory = new Inventory();
- theInventory.setItemName("Apples");
- theInventory.setSku(pk);
- theInventory.setVendorPrice(1.20f);
- theInventory.setVendorInventory(728);
- theInventory.setCategory("fruits");
- theInventory.setVendor("Off the Vine");
-
- inventoryBySku.put(theInventory);
-
- Inventory inventory = inventoryBySku.get(pk);
- System.out.println(ToStringBuilder.reflectionToString(inventory));
-
- boolean rs = inventoryBySku.delete(pk);
- Assert.assertTrue(rs);
-
- Assert.assertNull(inventoryBySku.get(pk));
-
- }
-
- //统计
- @Test
- public void count(){
- EntityCursor cursor = null;
- try{
- cursor = employerById.entities();
- int count = -1;
- if(cursor.next() != null){
- count = cursor.count();
- }
- System.out.println("employee count:" + count);
- }finally {
- if(cursor != null){
- cursor.close();
- }
- }
- }
-
- //级联及主键自增情况
- @Test
- public void sequencePk() {
-
- /*
- * Add a parent and two children using the Person primary index.
- * Specifying a non-null parentSsn adds the child Person to the
- * sub-index of children for that parent key.
- */
- personBySsn.put(new Person("Bob Smith", "111-11-1111", null));
- personBySsn.put(new Person("Mary Smith", "333-33-3333", "111-11-1111"));
- personBySsn.put(new Person("Jack Smith", "222-22-2222", "111-11-1111"));
-
- /* Print the children of a parent using a sub-index and a cursor. */
- EntityCursor children = personByParentSsn.subIndex("111-11-1111").entities();
- try {
- for (Person child : children) {
- System.out.println(child.getSsn() + ' ' + child.getName());
- }
- } finally {
- children.close();
- }
-
- /* Get Bob by primary key using the primary index. */
- Person bob = personBySsn.get("111-11-1111");
- Assert.assertNotNull(bob);
-
- /*
- * Create two employers if they do not already exist. Their primary
- * keys are assigned from a sequence.
- */
- Employer gizmoInc = employerByName.get("Gizmo Inc");
- if (gizmoInc == null) {
- gizmoInc = new Employer("Gizmo Inc");
- employerById.put(gizmoInc);
- }
- Employer gadgetInc = employerByName.get("Gadget Inc");
- if (gadgetInc == null) {
- gadgetInc = new Employer("Gadget Inc");
- employerById.put(gadgetInc);
- }
-
- /* Bob has two jobs and two email addresses. */
- bob.getEmployerIds().add(gizmoInc.getId());
- bob.getEmployerIds().add(gadgetInc.getId());
-
- bob.getEmailAddresses().add("bob@bob.com");
- bob.getEmailAddresses().add("bob@gmail.com");
-
- /* Update Bob's record. */
- personBySsn.put(bob);
-
- /* Bob can now be found by both email addresses. */
- bob = personByEmailAddresses.get("bob@bob.com");
- Assert.assertNotNull(bob);
- bob = personByEmailAddresses.get("bob@gmail.com");
- Assert.assertNotNull(bob);
-
- /* Bob can also be found as an employee of both employers. */
- EntityIndex employees;
- employees = personByEmployerIds.subIndex(gizmoInc.getId());
- Assert.assertTrue( employees.contains("111-11-1111"));
- employees = personByEmployerIds.subIndex(gadgetInc.getId());
- Assert.assertTrue(employees.contains("111-11-1111"));
-
- /*
- * When an employer is deleted, the onRelatedEntityDelete=NULLIFY for
- * the employerIds key causes the deleted ID to be removed from Bob's
- * employerIds.
- */
- employerById.delete(gizmoInc.getId());
- bob = personBySsn.get("111-11-1111");
- Assert.assertNotNull(bob);
- Assert.assertFalse(bob.getEmployerIds().contains(gizmoInc.getId()));
- }
-
- @Test
- public void cursor() {
- CursorConfig cc = new CursorConfig();
- // This is ignored if the store is not opened with uncommitted read
- // support.
- cc.setReadUncommitted(true);
-
- EntityCursor employers = employerById.entities(null, cc);
- try{
- for(Employer employer : employers){
- System.out.println(ToStringBuilder.reflectionToString(employer));
- }
- }finally{
- employers.close();
- }
- }
-
- @After
- public void close() {
- if (store != null) {
- try {
- store.close();
- } catch (DatabaseException dbe) {
- dbe.printStackTrace();
- }
- }
-
- if (myEnv != null) {
- try {
- // Finally, close the store and environment.
- myEnv.close();
- } catch (DatabaseException dbe) {
- dbe.printStackTrace();
- }
- }
- }
-}
+/*
+ * Copyright (c) 2018, hiwepy (https://github.com/hiwepy).
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License. You may obtain a copy of
+ * the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+package com.sleepycat.berkeley.spring.boot;
+
+import com.sleepycat.je.Database;
+import com.sleepycat.je.DatabaseConfig;
+import com.sleepycat.je.Environment;
+import com.sleepycat.je.EnvironmentConfig;
+import org.junit.jupiter.api.AfterEach;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.io.TempDir;
+import org.springframework.test.util.ReflectionTestUtils;
+
+import java.nio.file.Path;
+import java.util.Arrays;
+
+import static org.junit.jupiter.api.Assertions.*;
+
+class BerkeleyTest {
+ @TempDir Path home;
+ private Environment environment;
+ private Database database;
+ private BerkeleyTemplate template;
+
+ @BeforeEach
+ void openDatabase() {
+ EnvironmentConfig envConfig = new EnvironmentConfig();
+ envConfig.setAllowCreate(true);
+ envConfig.setTransactional(true);
+ environment = new Environment(home.toFile(), envConfig);
+ DatabaseConfig dbConfig = new DatabaseConfig();
+ dbConfig.setAllowCreate(true);
+ dbConfig.setTransactional(true);
+ database = environment.openDatabase(null, "items", dbConfig);
+ template = new BerkeleyTemplate();
+ template.setDatabase(database);
+ ReflectionTestUtils.setField(template, "myDbEnvironment", environment);
+ }
+
+ @AfterEach
+ void closeDatabase() {
+ if (database != null) database.close();
+ if (environment != null) environment.close();
+ }
+
+ @Test
+ void writesReadsListsAndDeletesTransactionalRecords() throws Exception {
+ assertSame(database, template.getDatabase());
+ template.writeToDatabase(" key ", " first ", false);
+ template.writeToDatabase("key", "ignored", false);
+ assertEquals("first", template.readFromDatabase("key"));
+ template.writeToDatabase("key", "second", true);
+ assertEquals("second", template.readFromDatabase("key"));
+ template.writeToDatabase("other", "value", false);
+ assertEquals(Arrays.asList("key", "other"), template.getAllFromDatabase());
+ template.deleteFromDatabase("other");
+ assertEquals("", template.readFromDatabase("other"));
+ }
+
+ @Test
+ void storesPrimitiveValues() {
+ template.writePrimitiveDatabase("primitive", "stored");
+ template.readPrimitiveDatabase("primitive");
+ assertNotEquals("", template.readFromDatabase("primitive"));
+ }
+
+
+ @Test
+ void truncatesAndReopensTheDatabase() {
+ template.writeToDatabase("keep", "before", true);
+ template.otherMethod();
+ database = template.getDatabase();
+ assertEquals("", template.readFromDatabase("keep"));
+ template.writeToDatabase("after", "value", true);
+ assertEquals("value", template.readFromDatabase("after"));
+ }
+}