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")); + } +}