Berkeley DB是历史悠久的嵌入式数据库系统,主要应用在UNIX/LINUX操作系统上,其设计思想是简单、小巧、可靠、高性能。
1. 下载
可去 官网下载,本文写作时的Java Edition(简称JE)最新版是Berkeley DB Java Edition 6.1.5。
另外,也可以用maven pom的方式来指定,这样就不用下载了(可参考上面这个地址上的链接)。
下载以后,解压后在lib目录下有个je-6.1.5.jar,加入到classpath就可以用了。Berkeley DB不需要像oracle,mysql那样先要启动数据库。因为他是嵌入式的,所以直接指定一个目录写文件就可以了。数据库文件的格式是00000000.jdb,00000001.jdb......
2. Base API
Berkeley DB读写数据库有2种API(Base API和DPL)。
先介绍第一种,Base API。
没啥好说的,看了代码就懂的。
public class BaseApiTest { public static void main(String[] args) throws Exception { EnvironmentConfig envConfig = new EnvironmentConfig(); envConfig.setAllowCreate(true); Environment dbEnv = new Environment(new File("D:/bdbtest/"), envConfig); DatabaseConfig dbconf = new DatabaseConfig(); dbconf.setAllowCreate(true); dbconf.setSortedDuplicates(false);//allow update Database db = dbEnv.openDatabase(null, "SampleDB", dbconf); DatabaseEntry searchEntry = new DatabaseEntry(); DatabaseEntry dataValue = new DatabaseEntry("data content".getBytes("UTF-8")); DatabaseEntry keyValue = new DatabaseEntry("key content".getBytes("UTF-8")); db.put(null, keyValue, dataValue);//inserting an entry } db.get(null, keyValue, searchEntry, LockMode.DEFAULT);//retrieving record String foundData = new String(searchEntry.getData(), "UTF-8"); System.out.println(foundData); dataValue = new DatabaseEntry("updated data content".getBytes("UTF-8")); db.put(null, keyValue, dataValue);//updating an entry db.delete(null, keyValue);//delete operation db.close(); dbEnv.close(); } }
这段代码先是创建了一个Environment,也就是数据库,指定数据写入目录为D:/bdbtest/。
然后插入一条key/value数据,key="key content", value="data content"
3.DPL
DPL(Direct Persistence Layer ),则相对Base API提供了更多的高级功能。有点类似hibernate/JPA这种了,可以直接将java bean保存到数据库。
首先定义2个java bean,Employee 和Project
@Entity(version=1) public class Employee { @PrimaryKey public String empID; public String lastname; @SecondaryKey(relate = Relationship.MANY_TO_ONE) public int age; @SecondaryKey(relate = Relationship.MANY_TO_ONE) public int sex; @SecondaryKey(relate = Relationship.MANY_TO_MANY, relatedEntity = Project.class, onRelatedEntityDelete = DeleteAction.NULLIFY) public Set<Long> projects; public Employee() { } public Employee(String empID, String lastname, int age, int sex, Set<Long> projects) { this.empID = empID; this.lastname = lastname; this.age = age; this.sex = sex; this.projects = projects; } }
@Entity(version=1) public class Project { public String projName; @PrimaryKey(sequence = "ID") public long projID; public Project() { } public Project(String projName) { this.projName = projName; } }
首先,@Entity类似于JPA,表示这是一个实体,或者表。
然后@PrimaryKey表示这张表的主键
@SecondaryKey先不要管。
我们通过下面这个程序测试一下。
public class DplTest { public static void main(String[] args) throws Exception { EnvironmentConfig envConfig = new EnvironmentConfig(); envConfig.setAllowCreate(true); Environment dbEnv = new Environment(new File("D:/bdbtest/"), envConfig); StoreConfig stConf = new StoreConfig(); stConf.setAllowCreate(true); EntityStore store = new EntityStore(dbEnv, "DPLSample", stConf); PrimaryIndex<String, Employee> userIndex; userIndex = store.getPrimaryIndex(String.class, Employee.class); userIndex.putNoReturn(new Employee("u180", "Doe", 20, 1, null));// insert Employee user = userIndex.get("u180");// retrieve System.out.println("empID=" + user.empID + ",lastname=" + user.lastname); userIndex.putNoReturn(new Employee("u180", "Locke", 30, 2, null));// Update userIndex.delete("u180");// delete store.close(); dbEnv.close(); } }
putNoReturn方法就是insert/update数据了,可以看到插入了一条u180的用户,很简单。
4. DPL高级
接下来讲一下@SecondaryKey,表示第二主键。有些字段如果需要查询的,则需要加上@SecondaryKey。
例子中Employee有一个age和sex,relate = Relationship.MANY_TO_ONE表示多个Employee的age和sex允许重复。如果改用Relationship.ONE_TO_ONE的话每个人的年龄就不能重复了,显然是不行的。
下面这句表示Employee和Project表有关联了,是多对多关系。
@SecondaryKey(relate = Relationship.MANY_TO_MANY, relatedEntity = Project.class, onRelatedEntityDelete = DeleteAction.NULLIFY) public Set<Long> projects;
好了,测试吧。
public class DplTest2 { public static void main(String[] args) throws Exception { EnvironmentConfig envConfig = new EnvironmentConfig(); envConfig.setAllowCreate(true); Environment dbEnv = new Environment(new File("D:/bdbtest/"), envConfig); StoreConfig stConf = new StoreConfig(); stConf.setAllowCreate(true); EntityStore store = new EntityStore(dbEnv, "DPLSample", stConf); PrimaryIndex<String, Employee> empByID; PrimaryIndex<Long, Project> projByID; empByID = store.getPrimaryIndex(String.class, Employee.class); projByID = store.getPrimaryIndex(Long.class, Project.class); SecondaryIndex<Long, String, Employee> empsByProject; empsByProject = store.getSecondaryIndex(empByID, Long.class, "projects"); Set<Long> projects = new HashSet<Long>(); Project proj = null; proj = new Project("Project 1"); projByID.putNoReturn(proj); projects.add(proj.projID); proj = new Project("Project 2"); projByID.putNoReturn(proj); projects.add(proj.projID); empByID.putNoReturn(new Employee("u150", "铃木五十郎", 20, 2, projects));//insert empByID.putNoReturn(new Employee("u144", "田中四郎", 20, 1, projects));//insert empByID.putNoReturn(new Employee("u146", "田中六郎", 30, 2, projects));//insert empByID.putNoReturn(new Employee("u147", "田中七郎", 20, 2, projects));//insert empByID.putNoReturn(new Employee("u148", "田中八郎", 30, 1, projects));//insert empByID.putNoReturn(new Employee("u149", "田中九郎", 20, 2, projects));//insert EntityIndex<String, Employee> projs = empsByProject.subIndex(proj.projID); EntityCursor<Employee> pcur = projs.entities(); System.out.println("----Employees----"); for (Employee user : pcur) { System.out.println("empID=" + user.empID + ",lastname=" + user.lastname); } pcur.close(); EntityCursor<Employee> emplRange = empByID.entities("e143", true, "u146", true); System.out.println("----Employees2----"); for (Employee user : emplRange) { System.out.println("empID=" + user.empID + ",lastname=" + user.lastname); } emplRange.close(); EntityJoin<String, Employee> join = new EntityJoin<String, Employee>(empByID); // For SecondaryIndex, the params are // 1st - type of the secondary index // 2nd - type of the primary key // 3rd - type of the stored object SecondaryIndex<Integer, String, Employee> employeeByAge = store.getSecondaryIndex(empByID, Integer.class, "age"); SecondaryIndex<Integer, String, Employee> employeeBySex = store.getSecondaryIndex(empByID, Integer.class, "sex"); //查找20岁,性别女的所有人 join.addCondition(employeeByAge, 20); join.addCondition(employeeBySex, 2); System.out.println("----Employees3----"); ForwardCursor<Employee> joinCursor = join.entities(); for (Employee user : joinCursor) { System.out.println("empID=" + user.empID + ",lastname=" + user.lastname); } joinCursor.close(); store.close(); dbEnv.close(); } }
我们的测试数据是u144~u150,年龄不是20就是30,然后性别不是1就是2(代表男女),每个人做的项目都是一样的,Project 1和Project 2。
测试结果
----Employees---- empID=u144,lastname=田中四郎 empID=u146,lastname=田中六郎 empID=u147,lastname=田中七郎 empID=u148,lastname=田中八郎 empID=u149,lastname=田中九郎 empID=u150,lastname=铃木五十郎 ----Employees2---- empID=u144,lastname=田中四郎 empID=u146,lastname=田中六郎 ----Employees3---- empID=u147,lastname=田中七郎 empID=u149,lastname=田中九郎 empID=u150,lastname=铃木五十郎
一共3个测试用例。
第一个,empsByProject.subIndex取得了做Project 1和Project 2的所有人,没问题。
第二个,empByID.entities("e143", true, "u146", true)表示取一个范围,id在e143到u146之间的,所以结果是2条记录(u144,u146)
第三个,通过EntityJoin.addCondition()这个方法查找20岁,性别女的所有人所以结果是3条记录(u147,u149,u150)
可以看到功能还是蛮丰富的,可以范围查找,还可以多条件过滤。
附件是本文提到的源代码。