0.概述
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)
可以看到功能还是蛮丰富的,可以范围查找,还可以多条件过滤。
附件是本文提到的源代码。