java之BerkeleyDB(二)--绑定(Binding)技术、游标(Cursor)
2014-03-07 10:26
344 查看
转自: http://blog.csdn.net/ylf13/article/details/15337957
有几个注意的,在BDB数据库里,默认是不能有重复的两个相同的键,当然可以通过config配置sortedDupli...来设置可以,所以在读取数据库值的时候必须考虑两种情况,是否存在相同的键的记录
JE provides two basic mechanisms for the storage and retrieval of database key/data pairs:
The
Cursors provide several methods for putting and getting database records. Cursors and their database access methods are described in Using
Cursors.
看完上段OK,如果是设置non-duplicate,那就直接用db.get() db.put()来操作记录。否则就得用Cursor了
delete函数:如果记录是支持duplicate,则删除所有满足的key的记录,如果想删除某一条,还是得用cursor
上篇我们简单的打开了数据库和进行简单的存储
这个对于我们存储数据的基本类型还行,但是涉及到用户自定义类的时候,单靠之前的转换函数来从string转换程对象是不妨便的,我们来看看BDB为我们准备来什么?
引自使用手册:
Note that due to performance considerations,you should not use Java serialization to convert a Java object to a
use the Bind APIs to perform this conversion (see Using
the BIND APIs for more information).
看到加粗这段了把,官方推荐我们用Bind
(一)Bind技术
(1)SeriaBinding
先说下序列化的绑定技术,言外之意,我们的数据类型就必须实现Serializable才能进行下面的绑定
Implement java.io.Serializable in the class whose instances that you want to store.
Open (create) your databases. You need two. The first is the database that you use to store your data. The second is used to store the class information.
Instantiate a class catalog. You do this with
Create an entry binding that uses
Instantiate an instance of the object that you want to store, and place it in a
其实绑定技术就是用了反射。
没看源码,也没什么好展开的,大家就把方法记着吧,以后再一步步来
由于需要用到Class这个类,所以构造函数多了一个value的Class
这样就可以使得我们自己数据完整的存入了
[cpp] view
plaincopy
import java.io.File;
import java.io.Serializable;
import java.io.UnsupportedEncodingException;
import com.sleepycat.bind.EntryBinding;
import com.sleepycat.bind.serial.SerialBinding;
import com.sleepycat.bind.serial.StoredClassCatalog;
import com.sleepycat.bind.serial.TupleSerialBinding;
import com.sleepycat.bind.tuple.TupleBase;
import com.sleepycat.bind.tuple.TupleBinding;
import com.sleepycat.bind.tuple.TupleTupleBinding;
import com.sleepycat.je.Database;
import com.sleepycat.je.DatabaseConfig;
import com.sleepycat.je.DatabaseEntry;
import com.sleepycat.je.Environment;
import com.sleepycat.je.EnvironmentConfig;
import com.sleepycat.je.LockMode;
import com.sleepycat.je.OperationStatus;
public class Main {
/**
* @param args
*/
static Environment env = null;
public static void main(String[] args) {
BDBUtil<Integer, Student> bDB = new BDBUtil<Integer, Student>("testDB",Student.class);
Student s1 = new Student(1,"ylf");
Student s2 = new Student(2,"dsb");
Student s3 = new Student(3,"dbc");
bDB.put(1, s1);
bDB.put(2, s2);
bDB.put(3, s3);
Student s = bDB.get(3);
System.out.println("my name is "+s.getName()+" no is "+s.getNo());
System.out.println(bDB.size());
bDB.close();
}
}
/**
* 我们的BDB工具
* 目前对外提供添加数据和取得数据,删除数据3个接口
* 类似HashMap的使用方法
* 注意:
* 这里的K 和 V两个类都必须实现来Serializable
* 而且也实现来toString
* 使用结束记得调用close()
* @author ylf
*
* 版本2:
* 采用动态的数据类型绑定,不是利用我们的toString()来转换对象和Entry
* 用到EntryBinding 和StoredClassCatalog
* 以及binding.OnjectToEntry() EntryToObject()
*
*/
class BDBUtil<K, V>{
private Environment env = null;
private EnvironmentConfig envCfig = null;
private Database db = null;
private DatabaseConfig dbCfig = null;
private Database classDB = null;
private StoredClassCatalog classCatalog = null;
private EntryBinding valueBinding = null;
private File file = null;
public BDBUtil(String dbName, Class valueClass) {
envCfig = new EnvironmentConfig();
envCfig.setAllowCreate(true);
file = new File("./test/");
env = new Environment(file, envCfig);
dbCfig = new DatabaseConfig();
dbCfig.setAllowCreate(true);
db = env.openDatabase(null, dbName, dbCfig);
//首先创建一个我们类的数据库
classDB = env.openDatabase(null, "classDB", dbCfig);
//实例化一个Catalog
classCatalog = new StoredClassCatalog(classDB);
//实例化一个binding来转换
valueBinding = new SerialBinding(classCatalog, valueClass);
}
public boolean put(K key, V value){
DatabaseEntry keyEntry = new DatabaseEntry(key.toString().getBytes());
DatabaseEntry valueEntry = new DatabaseEntry();
valueBinding.objectToEntry(value, valueEntry);
db.put(null, keyEntry, valueEntry);
return true;
}
public V get(K key){
DatabaseEntry keyEntry;
V value = null;
try {
keyEntry = new DatabaseEntry(key.toString().getBytes("gb2312"));
DatabaseEntry valueEntry = new DatabaseEntry();
if(db.get(null,keyEntry,valueEntry,LockMode.DEFAULT) == OperationStatus.SUCCESS){
value = (V)valueBinding.entryToObject(valueEntry);
return value;
}
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
}
return value;
}
public boolean del(K keyStr){
DatabaseEntry key;
try {
key = new DatabaseEntry(keyStr.toString().getBytes("gb2312"));
if(OperationStatus.SUCCESS == db.delete(null, key))
return true;
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
}
return false;
}
public long size(){
return db.count();
}
public void close(){
db.close();
classDB.close();
env.cleanLog();
env.close();
}
}
/**
* 序列化了的类
* 实现toString()
* @author ylf
*
*/
class Student implements Serializable{
/**
*
*/
private static final long serialVersionUID = 7333239714054069867L;
private String name;
private int no;
public Student() {
}
public Student(int no, String name){
this.no = no;
this.name = name;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getNo() {
return no;
}
public void setNo(int no) {
this.no = no;
}
@Override
public String toString() {
return "Student"+no+":"+name;
}
public void fromString(String str){
int i = str.indexOf(':');
String noStr = str.substring(7,i);
this.no = Integer.parseInt(noStr);
this.name = str.substring(i+1);
}
}
[cpp] view
plaincopy
my name is dbc no is 3
3
(2)自定义绑定
官方还推荐使用custom tuple binding
就是我们实现TupleBinding,实现里面的objectToEntry() EntryToObject()
这里就不需要维护第二个数据库了,有木有又回到远点的赶脚!!
还不如上一篇里直接在类里实现转换
只不过官方推荐的这种是用字节流来存储,省流量,我们类里也可以利用ArrayByteInputStream好像是这个。。。我忘了,就字节流来实现就好了
(二)游标cursor
游标操作类似数据库的游标。
这里通过getNext() getPrev()来实现遍历
同时,cursor还提供了查找和插入数据的功能,我这里就不再一一写出来了,具体用到的时候在设计吧,现在全部封装一遍也不见得很好。。
[cpp] view
plaincopy
interface BDBIterator{
public Object currentValue();
public Object currentKey();
public boolean hasNext();
public boolean hasPrev();
public void close();
}
这里迭代器实现的是BDBUtil的内部类,迭代器的实现大家可以参考Java的迭代器实现方法。
[cpp] view
plaincopy
public BDBIterator getIterator(){
IteratorImpl it = new IteratorImpl();
return it;
}
/**
* 这个内部类模拟iterator遍历器
* @author ylf
* 迭代器使用方法
* 首先利用BDBUtil获得迭代器
* hasNext()如果下一个元素存在,游标下移动,值通过currentKey currentValue获取
* hasPrev()向前移动
* 最后记得close() 虽然我这里已经通过null来保证自动close()但不是线程安全的
*
*/
class IteratorImpl implements BDBIterator{
K currentKey = null;
V currentValue = null;
DatabaseEntry keyEntry = null;
DatabaseEntry valueEntry = null;
public IteratorImpl() {
if(cursor != null){
cursor.close();
cursor = null;
}
cursor = db.openCursor(null, null);//这里不配值CursorConfig了
}
@Override
public void close(){
cursor.close();
cursor = null;
}
@Override
public Object currentKey() {
return currentKey;
}
@Override
public Object currentValue() {
return currentValue;
}
@Override
public boolean hasNext() {
keyEntry = new DatabaseEntry();
valueEntry = new DatabaseEntry();
cursor.getNext(keyEntry, valueEntry, LockMode.DEFAULT);
return has();
}
@Override
public boolean hasPrev() {
keyEntry = new DatabaseEntry();
valueEntry = new DatabaseEntry();
cursor.getPrev(keyEntry, valueEntry, LockMode.DEFAULT);
return has();
}
public boolean has(){
if(keyEntry.getData() == null)
return false;
try {
currentKey = (K) new String(keyEntry.getData(),"gb2312");
currentValue = (V) valueBinding.entryToObject(valueEntry);
if(currentValue != null)
return true;
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
}
return false;
}
}
调用方式如下:主要还是这个Iterator迭代器的实现遍历看下吧
[cpp] view
plaincopy
public static void main(String[] args) {
BDBUtil<Integer, Student> bDB = new BDBUtil<Integer, Student>("testDB",Student.class);
Student s1 = new Student(1,"ylf");
Student s2 = new Student(2,"dsb");
Student s3 = new Student(3,"dbc");
bDB.put(1, s1);
bDB.put(2, s2);
bDB.put(3, s3);
BDBIterator it = bDB.getIterator();
Student s = null;
int no=0;
while(it.hasNext()){
s = (Student)it.currentValue();
no = Integer.parseInt((String) it.currentKey());
System.out.println("my name is "+s.getName()+" no is "+s.getNo()+" "+no);
}
while(it.hasPrev()){
s = (Student)it.currentValue();
no = Integer.parseInt((String) it.currentKey());
System.out.println("my name is "+s.getName()+" no is "+s.getNo()+" "+no);
}
it.close();
BDBIterator it2 = bDB.getIterator();
while(it2.hasNext()){
s = (Student)it2.currentValue();
no = Integer.parseInt((String) it2.currentKey());
System.out.println("my name is "+s.getName()+" no is "+s.getNo()+" "+no);
}
it2.close();
System.out.println(bDB.size());
s = bDB.find(2);
System.out.println("find my name is "+s.getName());
bDB.close();
}
有几个注意的,在BDB数据库里,默认是不能有重复的两个相同的键,当然可以通过config配置sortedDupli...来设置可以,所以在读取数据库值的时候必须考虑两种情况,是否存在相同的键的记录
JE provides two basic mechanisms for the storage and retrieval of database key/data pairs:
The
Database.put()and
Database.get()methods provide the easiest access for all non-duplicate records in the database. These methods are described in this section.
Cursors provide several methods for putting and getting database records. Cursors and their database access methods are described in Using
Cursors.
看完上段OK,如果是设置non-duplicate,那就直接用db.get() db.put()来操作记录。否则就得用Cursor了
Database.put()
Database.putNoOverwrite()
Database.putNoDupData()
Database.get() 这个利用key来找
Database.getSearchBoth() 这个利用Key和value共同找记录
delete函数:如果记录是支持duplicate,则删除所有满足的key的记录,如果想删除某一条,还是得用cursor
上篇我们简单的打开了数据库和进行简单的存储
这个对于我们存储数据的基本类型还行,但是涉及到用户自定义类的时候,单靠之前的转换函数来从string转换程对象是不妨便的,我们来看看BDB为我们准备来什么?
引自使用手册:
DatabaseEntrycan hold any kind of data from simple Java primitive types to complex Java objects so long as that data can be represented as a Java
bytearray.
Note that due to performance considerations,you should not use Java serialization to convert a Java object to a
bytearray. Instead,
use the Bind APIs to perform this conversion (see Using
the BIND APIs for more information).
看到加粗这段了把,官方推荐我们用Bind
(一)Bind技术
(1)SeriaBinding
先说下序列化的绑定技术,言外之意,我们的数据类型就必须实现Serializable才能进行下面的绑定
Serializing Objects
To store a serializable complex object using the Bind APIs:Implement java.io.Serializable in the class whose instances that you want to store.
Open (create) your databases. You need two. The first is the database that you use to store your data. The second is used to store the class information.
Instantiate a class catalog. You do this with
com.sleepycat.bind.serial.StoredClassCatalog, and at that time you must provide a handle to an open database that is used to store the class information.
Create an entry binding that uses
com.sleepycat.bind.serial.SerialBinding.
Instantiate an instance of the object that you want to store, and place it in a
DatabaseEntryusing the entry binding that you created in the previous step.
其实绑定技术就是用了反射。
没看源码,也没什么好展开的,大家就把方法记着吧,以后再一步步来
由于需要用到Class这个类,所以构造函数多了一个value的Class
这样就可以使得我们自己数据完整的存入了
[cpp] view
plaincopy
import java.io.File;
import java.io.Serializable;
import java.io.UnsupportedEncodingException;
import com.sleepycat.bind.EntryBinding;
import com.sleepycat.bind.serial.SerialBinding;
import com.sleepycat.bind.serial.StoredClassCatalog;
import com.sleepycat.bind.serial.TupleSerialBinding;
import com.sleepycat.bind.tuple.TupleBase;
import com.sleepycat.bind.tuple.TupleBinding;
import com.sleepycat.bind.tuple.TupleTupleBinding;
import com.sleepycat.je.Database;
import com.sleepycat.je.DatabaseConfig;
import com.sleepycat.je.DatabaseEntry;
import com.sleepycat.je.Environment;
import com.sleepycat.je.EnvironmentConfig;
import com.sleepycat.je.LockMode;
import com.sleepycat.je.OperationStatus;
public class Main {
/**
* @param args
*/
static Environment env = null;
public static void main(String[] args) {
BDBUtil<Integer, Student> bDB = new BDBUtil<Integer, Student>("testDB",Student.class);
Student s1 = new Student(1,"ylf");
Student s2 = new Student(2,"dsb");
Student s3 = new Student(3,"dbc");
bDB.put(1, s1);
bDB.put(2, s2);
bDB.put(3, s3);
Student s = bDB.get(3);
System.out.println("my name is "+s.getName()+" no is "+s.getNo());
System.out.println(bDB.size());
bDB.close();
}
}
/**
* 我们的BDB工具
* 目前对外提供添加数据和取得数据,删除数据3个接口
* 类似HashMap的使用方法
* 注意:
* 这里的K 和 V两个类都必须实现来Serializable
* 而且也实现来toString
* 使用结束记得调用close()
* @author ylf
*
* 版本2:
* 采用动态的数据类型绑定,不是利用我们的toString()来转换对象和Entry
* 用到EntryBinding 和StoredClassCatalog
* 以及binding.OnjectToEntry() EntryToObject()
*
*/
class BDBUtil<K, V>{
private Environment env = null;
private EnvironmentConfig envCfig = null;
private Database db = null;
private DatabaseConfig dbCfig = null;
private Database classDB = null;
private StoredClassCatalog classCatalog = null;
private EntryBinding valueBinding = null;
private File file = null;
public BDBUtil(String dbName, Class valueClass) {
envCfig = new EnvironmentConfig();
envCfig.setAllowCreate(true);
file = new File("./test/");
env = new Environment(file, envCfig);
dbCfig = new DatabaseConfig();
dbCfig.setAllowCreate(true);
db = env.openDatabase(null, dbName, dbCfig);
//首先创建一个我们类的数据库
classDB = env.openDatabase(null, "classDB", dbCfig);
//实例化一个Catalog
classCatalog = new StoredClassCatalog(classDB);
//实例化一个binding来转换
valueBinding = new SerialBinding(classCatalog, valueClass);
}
public boolean put(K key, V value){
DatabaseEntry keyEntry = new DatabaseEntry(key.toString().getBytes());
DatabaseEntry valueEntry = new DatabaseEntry();
valueBinding.objectToEntry(value, valueEntry);
db.put(null, keyEntry, valueEntry);
return true;
}
public V get(K key){
DatabaseEntry keyEntry;
V value = null;
try {
keyEntry = new DatabaseEntry(key.toString().getBytes("gb2312"));
DatabaseEntry valueEntry = new DatabaseEntry();
if(db.get(null,keyEntry,valueEntry,LockMode.DEFAULT) == OperationStatus.SUCCESS){
value = (V)valueBinding.entryToObject(valueEntry);
return value;
}
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
}
return value;
}
public boolean del(K keyStr){
DatabaseEntry key;
try {
key = new DatabaseEntry(keyStr.toString().getBytes("gb2312"));
if(OperationStatus.SUCCESS == db.delete(null, key))
return true;
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
}
return false;
}
public long size(){
return db.count();
}
public void close(){
db.close();
classDB.close();
env.cleanLog();
env.close();
}
}
/**
* 序列化了的类
* 实现toString()
* @author ylf
*
*/
class Student implements Serializable{
/**
*
*/
private static final long serialVersionUID = 7333239714054069867L;
private String name;
private int no;
public Student() {
}
public Student(int no, String name){
this.no = no;
this.name = name;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getNo() {
return no;
}
public void setNo(int no) {
this.no = no;
}
@Override
public String toString() {
return "Student"+no+":"+name;
}
public void fromString(String str){
int i = str.indexOf(':');
String noStr = str.substring(7,i);
this.no = Integer.parseInt(noStr);
this.name = str.substring(i+1);
}
}
[cpp] view
plaincopy
my name is dbc no is 3
3
(2)自定义绑定
官方还推荐使用custom tuple binding
就是我们实现TupleBinding,实现里面的objectToEntry() EntryToObject()
这里就不需要维护第二个数据库了,有木有又回到远点的赶脚!!
还不如上一篇里直接在类里实现转换
只不过官方推荐的这种是用字节流来存储,省流量,我们类里也可以利用ArrayByteInputStream好像是这个。。。我忘了,就字节流来实现就好了
(二)游标cursor
游标操作类似数据库的游标。
这里通过getNext() getPrev()来实现遍历
同时,cursor还提供了查找和插入数据的功能,我这里就不再一一写出来了,具体用到的时候在设计吧,现在全部封装一遍也不见得很好。。
[cpp] view
plaincopy
interface BDBIterator{
public Object currentValue();
public Object currentKey();
public boolean hasNext();
public boolean hasPrev();
public void close();
}
这里迭代器实现的是BDBUtil的内部类,迭代器的实现大家可以参考Java的迭代器实现方法。
[cpp] view
plaincopy
public BDBIterator getIterator(){
IteratorImpl it = new IteratorImpl();
return it;
}
/**
* 这个内部类模拟iterator遍历器
* @author ylf
* 迭代器使用方法
* 首先利用BDBUtil获得迭代器
* hasNext()如果下一个元素存在,游标下移动,值通过currentKey currentValue获取
* hasPrev()向前移动
* 最后记得close() 虽然我这里已经通过null来保证自动close()但不是线程安全的
*
*/
class IteratorImpl implements BDBIterator{
K currentKey = null;
V currentValue = null;
DatabaseEntry keyEntry = null;
DatabaseEntry valueEntry = null;
public IteratorImpl() {
if(cursor != null){
cursor.close();
cursor = null;
}
cursor = db.openCursor(null, null);//这里不配值CursorConfig了
}
@Override
public void close(){
cursor.close();
cursor = null;
}
@Override
public Object currentKey() {
return currentKey;
}
@Override
public Object currentValue() {
return currentValue;
}
@Override
public boolean hasNext() {
keyEntry = new DatabaseEntry();
valueEntry = new DatabaseEntry();
cursor.getNext(keyEntry, valueEntry, LockMode.DEFAULT);
return has();
}
@Override
public boolean hasPrev() {
keyEntry = new DatabaseEntry();
valueEntry = new DatabaseEntry();
cursor.getPrev(keyEntry, valueEntry, LockMode.DEFAULT);
return has();
}
public boolean has(){
if(keyEntry.getData() == null)
return false;
try {
currentKey = (K) new String(keyEntry.getData(),"gb2312");
currentValue = (V) valueBinding.entryToObject(valueEntry);
if(currentValue != null)
return true;
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
}
return false;
}
}
调用方式如下:主要还是这个Iterator迭代器的实现遍历看下吧
[cpp] view
plaincopy
public static void main(String[] args) {
BDBUtil<Integer, Student> bDB = new BDBUtil<Integer, Student>("testDB",Student.class);
Student s1 = new Student(1,"ylf");
Student s2 = new Student(2,"dsb");
Student s3 = new Student(3,"dbc");
bDB.put(1, s1);
bDB.put(2, s2);
bDB.put(3, s3);
BDBIterator it = bDB.getIterator();
Student s = null;
int no=0;
while(it.hasNext()){
s = (Student)it.currentValue();
no = Integer.parseInt((String) it.currentKey());
System.out.println("my name is "+s.getName()+" no is "+s.getNo()+" "+no);
}
while(it.hasPrev()){
s = (Student)it.currentValue();
no = Integer.parseInt((String) it.currentKey());
System.out.println("my name is "+s.getName()+" no is "+s.getNo()+" "+no);
}
it.close();
BDBIterator it2 = bDB.getIterator();
while(it2.hasNext()){
s = (Student)it2.currentValue();
no = Integer.parseInt((String) it2.currentKey());
System.out.println("my name is "+s.getName()+" no is "+s.getNo()+" "+no);
}
it2.close();
System.out.println(bDB.size());
s = bDB.find(2);
System.out.println("find my name is "+s.getName());
bDB.close();
}
相关文章推荐
- java之BerkeleyDB(二)--绑定(Binding)技术、游标(Cursor)
- XML 和 Java 技术: 数据绑定的多种用法
- XML 与 Java 技术: 用 Castor 进行数据绑定
- XML 与 Java 技术: 用 Castor 进行数据绑定
- ORACLE语法-包(package)、存储过程(procedure)、游标(cursor)以及java对Result结果集的处理
- 关于“绑定技术”(binding)(续)
- Java late binding后期绑定与polymorphism多态的结合
- 关于“绑定(binding)”技术
- 揭秘自适应游标共享技术(Adaptive Cursor Sharing)
- Android DataBinding数据绑定技术在传统ListView中的使用简例
- XML 与 Java 技术: 用 Castor 进行数据绑定
- 关于“绑定技术”(binding)(续)
- XML 与 Java 技术: 用 Castor 进行数据绑定
- jface databinding:可多选的widget List组件selection项目与java.util.List对象的双向数据绑定
- 关于“绑定(binding)”技术
- XML 和 Java 技术: 数据绑定的多种用法
- Day60-Oracle04 - PLSQL编程、游标cursor、例外exception、存储过程(procedure)、存储函数(function)、java调用存储过程、触发器(trigger)
- XML 和 Java 技术: 数据绑定的多种用法
- java读取ORACLE 存储过程 返回游标(cursor) 格式 读取到List中
- 自适应游标共享技术(Adaptive Cursor Sharing)