Berkeley database (JE)操作与下载

来源:互联网 发布:windows ce版本 编辑:程序博客网 时间:2024/06/06 17:04

一、 简介


       Berkeley DB Java Edition (JE)是一个完全用JAVA写的,它适合于管理海量的,简单的数据。

    l 能够高效率的处理1到1百万条记录,制约JE数据库的往往是硬件系统,而不是JE本身。

    l 多线程支持,JE使用超时的方式来处理线程间的死琐问题。

    l Database都采用简单的key/value对应的形式。

   l 事务支持。

   l 允许创建二级库。这样我们就可以方便的使用一级key,二级key来访问我们的数据。

   l 支持RAM缓冲,这样就能减少频繁的IO操作。

   l 支持日志。

   l 数据备份和恢复。

   l 游标支持。

二、 安装JE

     JE下载地址:

      http://www.oracle.com/technology/software/products/berkeley-db/je/index.html

      解开包后 把JE_HOME/lib/je-.jar 中的jar文件添加到你的环境变量中就可以使用je了。

     相关帮助文档可以参考 JE_HOME/docs/index.html

     源代码见JE_HOME/src/*.*

三、 JE常见的异常

    DatabaseNotFoundException 当没有找到指定的数据库的时候会返回这个异常

     DeadlockException 线程间死锁异常

     RunRecoveryException 回收异常,当发生此异常的时候,你必须得重新打开环境变量。

四、 关于日志文件必须了解的六项

      JE的日志文件跟其他的数据库的日志文件不太一样,跟C版的DBD也是有区别的

      l JE的日志文件只能APPEND,第一个日志文件名是 00000000.jdb,当他增长到一定大小的时候(默认是10M),开始写第二个日志文件00000001.jdb,已此类推。

     l 跟C版本有所不同,JE的数据日志和事务日志是放在一起的,而不是分开放的。

     l JE cleaner负责清扫没用到的磁盘空间,删除后,或者更新后新的记录会追加进来,而原有的记录空间就不在使用了,cleaner负责清理不用的空间。

     l 清理并不是立即进行的,当你关闭你的数据库环境后,通过调用一个cleaner方法来清理。

     l 清理也不是只动执行的,需要你自己手动调用cleaner 方法来定时清理的。

     l 日志文件的删除仅发生在检查点之后。cleaner准备出哪些log 文件需要被删除,当检查点过后,删掉一些不在被使用的文件。每写20M的日志文件就执行一次检查点,默认          下。

五、 创建数据库环境

     JE要求在任何DATABASE操作前,要先打开数据库环境,就像我们要使用数据库的话必须得先建立连接一样。你可以通过数据库环境来创建和打开database,或者更改database名称和删除database.可以通过Environments对象来打开环境,打开环境的时候设置的目录必须是已经存在的目录,否则会出错误。默认情况下,如果指定的database不存在则不会自动创建一个新的detabase,但可以通过设置setAllowCreate来改变这一情况。

      1. 打开database环境
       
package je.gettingStarted;import com.sleepycat.je.DatabaseException;import com.sleepycat.je.Environment;import com.sleepycat.je.EnvironmentConfig;import java.io.File;...Environment myDbEnvironment = null;try {    EnvironmentConfig envConfig = new EnvironmentConfig();    <pre name="code" class="java">    //如果不存在则创建一个
    envConfig.setAllowCreate(true);    myDbEnvironment = new Environment(new File("/export/dbEnv"), envConfig);} catch (DatabaseException dbe) {    // 错误处理}

     2. 关闭database环境

     可以通过Environment.close()这个方法来关闭database环境,当你完成数据库操作后一定要关闭数据库环境。


示例:


import com.sleepycat.je.DatabaseException;


import com.sleepycat.je.Environment;


...


try {


    if (myDbEnvironment != null) {


        myDbEnvironment.close();


    }


} catch (DatabaseException dbe) {


    // Exception handling goes here


}


3. 清理日志


通常在关闭数据库连接的时候,有必要清理下日志,用以释放更多的磁盘空间。我们可以在Environment.close前执行下Environment.cleanLog()来达到此目的。


示例:


import com.sleepycat.je.DatabaseException;


import com.sleepycat.je.Environment;


...


try {


    if (myDbEnvironment != null) {


        myDbEnvironment.cleanLog(); // 在关闭环境前清理下日志


        myDbEnvironment.close();


    }


} catch (DatabaseException dbe) {


    // Exception handling goes here


}


4. Database环境的配置


可以通过EnvironmentConfig这个对象来配置database环境。如果想得到当前环境的配置信息则可以通过Environment.getConfig()方法得到当前环境的配置信息。


也可以使用EnvironmentMutableConfig来配置环境,其实 EnvironmentConfig是EnvironmentMutableConfig的子类,所以EnvironmentMutableConfig能够使用的设置,EnvironmentConfig也同样能够使用。


如果你要获取当前环境的使用情况,那么你可以通过使用EnvironmentStats.getNCacheMiss().来监视RAM cache命中率。EnvironmentStats可以由Environment.getStats()方法获取。


EnvironmentConfig常见方法介绍


l EnvironmentConfig.setAllowCreate() ;


如果设置了true则表示当数据库环境不存在时候重新创建一个数据库环境,默认为false.


l EnvironmentConfig.setReadOnly()


以只读方式打开,默认为false.


l EnvironmentConfig.setTransactional()


事务支持,如果为true,则表示当前环境支持事务处理,默认为false,不支持事务处理。


EnvironmentMutableConfig的介绍


l setCachePercent()


设置当前环境能够使用的RAM占整个JVM内存的百分比。


l setCacheSize()


设置当前环境能够使用的最大RAM。单位BYTE


l setTxnNoSync()


当提交事务的时候是否把缓存中的内容同步到磁盘中去。


true 表示不同步,也就是说不写磁盘


l setTxnWriteNoSync()


当提交事务的时候,是否把缓冲的log写到磁盘上


true 表示不同步,也就是说不写磁盘


示例一:


package je.gettingStarted;


import com.sleepycat.je.DatabaseException;


import com.sleepycat.je.Environment;


import com.sleepycat.je.EnvironmentConfig;


import java.io.File;


...


Environment myDatabaseEnvironment = null;


try {


    EnvironmentConfig envConfig = new EnvironmentConfig();


    //当环境不存在的时候自动创建环境


       envConfig.setAllowCreate(true);


       //设置支持事务


       envConfig.setTransactional(true);


    myDatabaseEnvironment =


        new Environment(new File("/export/dbEnv"), envConfig);


} catch (DatabaseException dbe) {


   System.err.println(dbe.toString());


   System.exit(1);


}


示例二:


package je.gettingStarted;


import com.sleepycat.je.DatabaseException;


import com.sleepycat.je.Environment;


import com.sleepycat.je.EnvironmentMutableConfig;


import java.io.File;


...


try {


    Environment myEnv = new Environment(new File("/export/dbEnv"), null);


    EnvironmentMutableConfig envMutableConfig =


        new EnvironmentMutableConfig();


    envMutableConfig.setTxnNoSync(true);


    myEnv.setMutableConfig(envMutableConfig);


} catch (DatabaseException dbe) {


    // Exception handling goes here


}


示例三:


import com.sleepycat.je.Environment;


...


//没有命中的CACHE


long cacheMisses = myEnv.getStats(null).getNCacheMiss();


...


5. Database操作


在BDB中,数据是以key/value方式成队出现的。


打开database


可以通过environment.openDatabase()方法打开一个database,在调用这个方法的时候必须指定database的名称。和databaseConfig() (注:数据库设置)


示例:


package je.gettingStarted;


import com.sleepycat.je.Database;


import com.sleepycat.je.DatabaseConfig;


import com.sleepycat.je.DatabaseException;


import com.sleepycat.je.Environment;


import com.sleepycat.je.EnvironmentConfig;


import java.io.File;


...


Environment myDbEnvironment = null;


Database myDatabase = null;


...


try {


    // 打开一个环境,如果不存在则创建一个


    EnvironmentConfig envConfig = new EnvironmentConfig();


    envConfig.setAllowCreate(true);


    myDbEnvironment = new Environment(new File("/export/dbEnv"), envConfig);


    // 打开一个数据库,如果数据库不存在则创建一个


    DatabaseConfig dbConfig = new DatabaseConfig();


dbConfig.setAllowCreate(true);


    myDatabase = myDbEnvironment.openDatabase(null,


"sampleDatabase", dbConfig); //打开一个数据库,数据库名为


                                   //sampleDatabase,数据库的配置为dbConfig


} catch (DatabaseException dbe) {


    // 错误处理


}


关闭database


通过调用Database.close()方法来关闭数据库,但要注意,在关闭数据库前必须得先把游标先关闭。


使用示例:


import com.sleepycat.je.DatabaseException;


import com.sleepycat.je.Database;


import com.sleepycat.je.Environment;


...


try {


        if (myDatabase != null) {


            myDatabase.close();


        }


        if (myDbEnvironment != null) {


            myDbEnvironment.close();


        }


} catch (DatabaseException dbe) {


    // 错误处理


}


设置数据库属性


其实设置数据库属性跟设置环境属性差不多,JE中通过DatabaseConfig对象来设置数据库属性。你能够设置的数据库属性如下。


l DatabaseConfig.setAllowCreate()


如果是true的话,则当不存在此数据库的时候创建一个。


l DatabaseConfig.setBtreeComparator()


设置用于Btree比较的比较器,通常是用来排序


l DatabaseConfig.setDuplicateComparator()


设置用来比较一个key有两个不同值的时候的大小比较器。


l DatabaseConfig.setSortedDuplicates()


设置一个key是否允许存储多个值,true代表允许,默认false.


l DatabaseConfig.setExclusiveCreate()


以独占的方式打开,也就是说同一个时间只能有一实例打开这个database。


l DatabaseConfig.setReadOnly()


以只读方式打开database,默认是false.


l DatabaseConfig.setTransactional()


如果设置为true,则支持事务处理,默认是false,不支持事务。


使用示例:


package je.gettingStarted;


import com.sleepycat.je.DatabaseException;


import com.sleepycat.je.Database;


import com.sleepycat.je.DatabaseConfig;


...


// Environment open omitted for brevity


...


Database myDatabase = null;


try {


    DatabaseConfig dbConfig = new DatabaseConfig();


    dbConfig.setAllowCreate(true);


    dbConfig.setSortedDuplicates(true);


    myDatabase =


        myDbEnv.openDatabase(null,


                             "sampleDatabase",


                             dbConfig);


} catch (DatabaseException dbe) {


    // Exception handling goes here.


}


一些用来管理的方法


l Database.getDatabaseName()


取得数据库的名称


如:String dbName = myDatabase.getDatabaseName();


l Database.getEnvironment()


取得包含这个database的环境信息


如:Environment theEnv = myDatabase.getEnvironment();


l Database.preload()


预先加载指定bytes的数据到RAM中。


如:myDatabase.preload(1048576l); // 1024*1024


l Environment.getDatabaseNames()


返回当前环境下的数据库列表


如:


import java.util.List;


List myDbNames = myDbEnv.getDatabaseNames();


for(int i=0; i < myDbNames.size(); i++) {


    System.out.println("Database Name: " + (String)myDbNames.get(i));


}


l Environment.removeDatabase()


删除当前环境中指定的数据库。


如:


String dbName = myDatabase.getDatabaseName();


myDatabase.close();


myDbEnv.removeDatabase(null, dbName);


l Environment.renameDatabase()


给当前环境下的数据库改名


如:


String oldName = myDatabase.getDatabaseName();


String newName = new String(oldName + ".new", "UTF-8");


myDatabase.close();


myDbEnv.renameDatabase(null, oldName, newName);


l Environment.truncateDatabase()


清空database内的所有数据,返回清空了多少条记录。


如:


Int numDiscarded= myEnv.truncate(null,


myDatabase.getDatabaseName(),true);


System.out.println("一共删除了 " + numDiscarded +" 条记录 从数据库 " + myDatabase.getDatabaseName());


6. Database 记录


JE的记录包含两部分,key键值和value数据值,这两个值都是通过DatabaseEntry对象封装起来,所以说如果要使用记录,则你必须创建两个DatabaseEntry对象,一个是用来做为key,另外一个是做为value.


DatabaseEntry能够支持任何的能够转换为bytes数组形式的基本数据。包括所有的JAVA基本类型和可序列化的对象.




使用记录


示例一:把字符串转换DatabaseEntry


package je.gettingStarted;


import com.sleepycat.je.DatabaseEntry;


...


String aKey = "key";


String aData = "data";


try {


//设置key/value,注意DatabaseEntry内使用的是bytes数组


DatabaseEntry theKey=new DatabaseEntry(aKey.getBytes("UTF-8"));


DatabaseEntry theData=new DatabaseEntry(aData.getBytes("UTF-8"));


} catch (Exception e) {


    // 错误处理


}


示例二:把DatabaseEntry里的数据转换成字符串


byte[] myKey = theKey.getData();


byte[] myData = theData.getData();


String key = new String(myKey, "UTF-8");


String data = new String(myData, "UTF-8");


读和写database 记录


读和写database记录的时候大体是基本一样的,唯一有区别的是每个key写是否允许写多条记录,默认情况下是不支持多条记录的。


a) 你可以使用如下方法向database 里添加记录


l Database.put()


向database中添加一条记录。如果你的database不支持一个key对应多个data或当前database中已经存在该key了,则使用此方法将使用新的值覆盖旧的值。


l Database.putNoOverwrite()


向database中添加新值但如果原先已经有了该key,则不覆盖。不管database是否允许支持多重记录(一个key对应多个value),只要存在该key就不允许添加,并且返回perationStatus.KEYEXIST信息。


l Database.putNoDupData()


想database中添加一条记录,如果database中已经存在了相同的 key和value则返回 OperationStatus.KEYEXIST.


使用示例:


package je.gettingStarted;


import com.sleepycat.je.Database;


import com.sleepycat.je.DatabaseEntry;


...


String aKey = "myFirstKey";


String aData = "myFirstData";


try {


    DatabaseEntry theKey = new DatabaseEntry(aKey.getBytes("UTF-8"));


    DatabaseEntry theData = new DatabaseEntry(aData.getBytes("UTF-8"));


    myDatabase.put(null, theKey, theData);


} catch (Exception e) {


    // Exception handling goes here


}


b) 你可以使用如下方法从database 里读取记录


1. Database.get()


基本的读记录的方法,通过key的方式来匹配,如果没有改记录则返回OperationStatus.NOTFOUND。


l Database.getSearchBoth()


通过key和value来同时匹配,同样如果没有记录匹配key和value则会返回OperationStatus.NOTFOUND。


使用示例:


package je.gettingStarted;


import com.sleepycat.je.Database;


import com.sleepycat.je.DatabaseEntry;


import com.sleepycat.je.LockMode;


import com.sleepycat.je.OperationStatus;


...


String aKey = "myFirstKey";


try {


    DatabaseEntry theKey = new DatabaseEntry(aKey.getBytes("UTF-8"));


    DatabaseEntry theData = new DatabaseEntry();


if (myDatabase.get(null, theKey, theData, LockMode.DEFAULT) ==


        OperationStatus.SUCCESS) {


        byte[] retData = theData.getData();


        String foundData = new String(retData, "UTF-8");


        System.out.println("For key: '" + aKey + "' found data: '" +


                            foundData + "'.");


    } else {


        System.out.println("No record found for key '" + aKey + "'.");


    }


} catch (Exception e) {


    // Exception handling goes here


}


c) 删除记录


可以使用Database.delete()这个方法来删除记录。如果你的database支持多重记录,则当前key下的所有记录都会被删除,如果只想删除多重记录中的一条则可以使用游标来删除。


当然你也可以使用Environment.truncateDatabase()这个方法来清空database 中的所有记录。




使用示例:


package je.gettingStarted;


import com.sleepycat.je.Database;


import com.sleepycat.je.DatabaseEntry;


...


try {


    String aKey = "myFirstKey";


    DatabaseEntry theKey = new DatabaseEntry(aKey.getBytes("UTF-8"));


    myDatabase.delete(null, theKey);


} catch (Exception e) {


}


d) 提交事务


当你对database进行了写操作的时候,你的修改不一定马上就能生效,有的时候他仅仅是缓存在RAM中,如果想让你的修改立即生效,则可以使用Environment.sync()方法来把数据同步到磁盘中去。


e) 不同类型的数据的处理


1. 你可以使用DatabaseEntry来绑定基本的JAVA数据类型,主要有String、Character、Boolean、Byte、Short、Integer、Long、Float、Double.


使用示例一:


package je.gettingStarted;


import com.sleepycat.bind.EntryBinding;


import com.sleepycat.bind.tuple.TupleBinding;


import com.sleepycat.je.DatabaseEntry;


...


try {


    String aKey = "myLong";


    DatabaseEntry theKey = new


    DatabaseEntry(aKey.getBytes("UTF-8"));   


    Long myLong = new Long(123456789l);


DatabaseEntry theData = new DatabaseEntry();


EntryBinding myBinding =


    TupleBinding.getPrimitiveBinding(Long.class);


    myBinding.objectToEntry(myLong, theData);


    myDatabase.put(null, theKey, theData);


} catch (Exception e) {


    // Exception handling goes here


}


使用示例二:


package je.gettingStarted;


import com.sleepycat.bind.EntryBinding;


import com.sleepycat.bind.tuple.TupleBinding;


import com.sleepycat.je.Database;


import com.sleepycat.je.DatabaseEntry;


import com.sleepycat.je.LockMode;


import com.sleepycat.je.OperationStatus;


...


Database myDatabase = null;


try {


       String aKey = "myLong";


       DatabaseEntry theKey = new


       DatabaseEntry(aKey.getBytes("UTF-8"));


DatabaseEntry theData = new DatabaseEntry();


EntryBinding myBinding =       


       TupleBinding.getPrimitiveBinding(Long.class);


       OperationStatus retVal = myDatabase.get(null, theKey, theData,


       LockMode.DEFAULT);


       String retKey = null;


       if (retVal == OperationStatus.SUCCESS) {


    Long theLong = (Long) myBinding.entryToObject(theData);


           retKey = new String(theKey.getData(), "UTF-8");


           System.out.println("For key: '" + retKey + "' found Long: '" +


                        theLong + "'.");


       } else {


           System.out.println("No record found for key '" + retKey + "'.");


       }


} catch (Exception e) {


       // Exception handling goes here


}


2. 可序列化的对象的绑定


1. 首先你需要创建一个可序列化对象


2. 打开或创建你的database,你需要两个,一个用来存储你的数据,另外一个用来存储类信息。


3. 实例化catalog类,这个时候你可以使用com.sleepycat.bind.serial.StoredClassCatalog,来存储你的类信息。


4. 通过com.sleepycat.bind.serial.SerialBinding来绑定数据和类。


5. 绑定并存储数据。


示例:


l 创建一个可序列化的对象


package je.gettingStarted;


import java.io.Serializable;


public class MyData implements Serializable {


    private long longData;


    private double doubleData;


    private String description;


    MyData() {


        longData = 0;


        doubleData = 0.0;


        description = null;


    }


    public void setLong(long data) {


        longData = data;


    }


    public void setDouble(double data) {


        doubleData = data;


    }


    public void setDescription(String data) {


        description = data;


    }


    public long getLong() {


        return longData;


    }


    public double getDouble() {


        return doubleData;


    }


    public String getDescription() {


        return description;


    }


}


l 存储数据


package je.gettingStarted;


import com.sleepycat.bind.EntryBinding;


import com.sleepycat.bind.serial.StoredClassCatalog;


import com.sleepycat.bind.serial.SerialBinding;


import com.sleepycat.je.Database;


import com.sleepycat.je.DatabaseConfig;


import com.sleepycat.je.DatabaseEntry;


...


String aKey = "myData";


MyData data2Store = new MyData();


data2Store.setLong(123456789l);


data2Store.setDouble(1234.9876543);


data2Store.setDescription("A test instance of this class");


try {


    DatabaseConfig myDbConfig = new DatabaseConfig();


    myDbConfig.setAllowCreate(true);


    myDbConfig.setSortedDuplicates(true);


    Database myDatabase = myDbEnv.openDatabase(null, "myDb", myDbConfig);


    myDbConfig.setSortedDuplicates(false);


//打开用来存储类信息的库


    Database myClassDb = myDbEnv.openDatabase(null, "classDb", myDbConfig);


    // 3)创建catalog


    StoredClassCatalog classCatalog = new StoredClassCatalog(myClassDb);


  // 4)绑定数据和类


    EntryBinding dataBinding = new SerialBinding(classCatalog,


                                                 MyData.class);


    DatabaseEntry theKey = new DatabaseEntry(aKey.getBytes("UTF-8"));


  // 向DatabaseEntry里写数据


    DatabaseEntry theData = new DatabaseEntry();


    dataBinding.objectToEntry(data2Store, theData);


    myDatabase.put(null, theKey, theData);


} catch (Exception e) {


    // 错误处理


}


l 读数据


package je.gettingStarted;


import com.sleepycat.bind.EntryBinding;


import com.sleepycat.bind.serial.StoredClassCatalog;


import com.sleepycat.bind.serial.SerialBinding;


import com.sleepycat.je.Database;


import com.sleepycat.je.DatabaseConfig;


import com.sleepycat.je.DatabaseEntry;


import com.sleepycat.je.LockMode;


...


// The key data.


String aKey = "myData";


try {


    DatabaseConfig myDbConfig = new DatabaseConfig();


    myDbConfig.setAllowCreate(false);


    Database myDatabase = myDbEnv.openDatabase(null, "myDb", myDbConfig);


       //用来存储类信息的库


Database myClassDb = myDbEnv.openDatabase(null, "classDb", myDbConfig);


// 实例化catalog


    StoredClassCatalog classCatalog = new StoredClassCatalog(myClassDb);


// 创建绑定对象


    EntryBinding dataBinding = new SerialBinding(classCatalog,


                                                 MyData.class);


    DatabaseEntry theKey = new DatabaseEntry(aKey.getBytes("UTF-8"));


    DatabaseEntry theData = new DatabaseEntry();


    myDatabase.get(null, theKey, theData, LockMode.DEFAULT);


    // Recreate the MyData object from the retrieved DatabaseEntry using


    // 根据存储的类信息还原数据


MyData retrievedData=(MyData)dataBinding.entryToObject(theData);


} catch (Exception e) {


    // Exception handling goes here


}


3. 自定义对象的绑定


使用tuple binding 来绑定自定义数据的步骤


①. 实例化你要存储的对象


②. 通过com.sleepycat.bind.tuple.TupleBinding class来创建一个tuple binding。


③. 创建一个database,跟序列化的对象不同,你只需要创建一个。


④. 通过继承第二步的类来创建一个entry binding 对象。


⑤. 存储和使用数据


使用示例:


l 创建要存储的对象


package je.gettingStarted;


public class MyData2 {


    private long longData;


    private Double doubleData;


    private String description;


    public MyData2() {


        longData = 0;


        doubleData = new Double(0.0);


        description = "";


    }


    public void setLong(long data) {


        longData = data;


    }


    public void setDouble(Double data) {


        doubleData = data;


    }


    public void setString(String data) {


        description = data;


    }


    public long getLong() {


        return longData;


    }


    public Double getDouble() {


        return doubleData;


    }


    public String getString() {


        return description;


    }


}


l 创建一个TupleBinding对象


package je.gettingStarted;


import com.sleepycat.bind.tuple.TupleBinding;


import com.sleepycat.bind.tuple.TupleInput;


import com.sleepycat.bind.tuple.TupleOutput;


public class MyTupleBinding extends TupleBinding {


    // 把对象转换成TupleOutput


    public void objectToEntry(Object object, TupleOutput to) {


        MyData2 myData = (MyData2)object;


to.writeDouble(myData.getDouble().doubleValue());


        to.writeLong(myData.getLong());


        to.writeString(myData.getString());


    }


   //把TupleInput转换为对象


    public Object entryToObject(TupleInput ti) {


Double theDouble = new Double(ti.readDouble());


        long theLong = ti.readLong();


        String theString = ti.readString();


        MyData2 myData = new MyData2();


        myData.setDouble(theDouble);


        myData.setLong(theLong);


        myData.setString(theString);


        return myData;


    }


}


l  读和写数据


package je.gettingStarted;


import com.sleepycat.bind.tuple.TupleBinding;


import com.sleepycat.je.DatabaseEntry;


...


TupleBinding keyBinding = new MyTupleBinding();


MyData2 theKeyData = new MyData2();


theKeyData.setLong(123456789l);


theKeyData.setDouble(new Double(12345.6789));


theKeyData.setString("My key data");


DatabaseEntry myDate = new DatabaseEntry();


try {


    // 把theKeyData 存储到DatabaseEntry里


    keyBinding.objectToEntry(theKeyData, myDate);


    ...


    // Database 进行了一些读和写操作


    ...


    // Retrieve the key data


    theKeyData = (MyData2) keyBinding.entryToObject(myDate);


} catch (Exception e) {


    // 错误处理


}


f) 使用比较器


JE是使用BTrees来组织结构的,这意味着当对database的读和写需要涉及BTrees间的节点比较。这些比较在key间是经常的发生的。如果你的database支持多重记录,那么也会存在data间的比较。


默认的情况JE的比较器是按照字节的方式来进行比较的,这通常情况下能处理大多数的情况。但有的时候确实需要自定义比较器用于特殊的通途,比如说按照key来排序。


l 创建自己的比较器


其实很简单,只要你重写Comparator class中的比较方法(compare)就可以了,通过Comparator.compare()会传递给你两个byte 数组形式的值,如果你知道结构,则可以根据你自己定义的方法来进行比较




示例:


package je.gettingStarted;


import java.util.Comparator;


public class MyDataComparator implements Comparator {


    public MyDataComparator() {}


    public int compare(Object d1, Object d2) {


        byte[] b1 = (byte[])d1;


        byte[] b2 = (byte[])d2;


        String s1 = new String(b1, "UTF-8");


        String s2 = new String(b2, "UTF-8");


return s1.compareTo(s2);


    }


}


l 让database使用你自定义的比较器


如果你想改变database中基本的排序方式,你只能重新创建database并重新导入数据。


①. DatabaseConfig.setBtreeComparator()


用于在database里两个key的比较


②. DatabaseConfig.setOverrideBtreeComparator()


如果为true则代表让database使用 DatabaseConfig.setBtreeComparator()设置的比较器来代替默认的比较器。


③. DatabaseConfig.setDuplicateComparator()


用于database可以使用多重记录的时候的data的 比较。


④. DatabaseConfig.setOverrideDuplicateComparator()


如果为true则代表让database使用 DatabaseConfig. setDuplicateComparator()设置 的比 较器来代替默认的比较器。


使用示例:


package je.gettingStarted;


import com.sleepycat.je.Database;


import com.sleepycat.je.DatabaseConfig;


import com.sleepycat.je.DatabaseException;


import java.util.Comparator;   


...


try {


    DatabaseConfig myDbConfig = new DatabaseConfig();


    myDbConfig.setAllowCreate(true);


// 设置要使用的比较器


    myDbConfig.setDuplicateComparator(MyDataComparator.class);


    // 使用自己定义的比较器


    myDbConfig.setSortedDuplicates(true);


    Database myDatabase = myDbEnv.openDatabase(null, "myDb", myDbConfig);


} catch (DatabaseException dbe) {


    // Exception handling goes here


}


六、 游标的使用


游标提供了遍历你database中记录的一种机制,使用游标你可以获取,添加,和删除你的记录。如果你的database支持多重记录,则可以通过游标访问同一个key下的每一个记录。


l 打开和关闭游标


要想使用游标则你必须通过Database.openCursor()方法来打开一个游标,你可以通过CursorConfig来配置你的游标。


可以通过Cursor.close()方法来关闭游标。请注意在关闭database和环境前一定要关闭游标,否则会带来错误。


打开游标示例:


package je.gettingStarted;


import com.sleepycat.je.Cursor;


import com.sleepycat.je.CursorConfig;


import com.sleepycat.je.Database;


import com.sleepycat.je.DatabaseException;


import com.sleepycat.je.Environment;


import java.io.File;


...


Environment myDbEnvironment = null;


Database myDatabase = null;


Cursor myCursor = null;


try {


    myDbEnvironment = new Environment(new File("/export/dbEnv"), null);


    myDatabase = myDbEnvironment.openDatabase(null, "myDB", null);


    myCursor = myDatabase.openCursor(null, null);


} catch (DatabaseException dbe) {


    // Exception handling goes here ...


}


关闭游标示例:


package je.gettingStarted;


import com.sleepycat.je.Cursor;


import com.sleepycat.je.Database;


import com.sleepycat.je.Environment;


...


try {


    ...


} catch ... {


} finally {


    try {


        if (myCursor != null) {


            myCursor.close();


        }


        if (myDatabase != null) {


            myDatabase.close();


        }


        if (myDbEnvironment != null) {


            myDbEnvironment.close();


        }


    } catch(DatabaseException dbe) {


        System.err.println("Error in close: " + dbe.toString());


    }


}


l 通过游标来获取记录


可以通过游标的Cursor.getNext()方法来遍历记录,Cursor.getNext()表示游标指针向下移动一条记录。同样的Cursor.getPrev()表示游标指针向上移动一条记录。


使用示例一:


package je.gettingStarted;


import com.sleepycat.je.Cursor;


import com.sleepycat.je.Database;


import com.sleepycat.je.DatabaseEntry;


import com.sleepycat.je.DatabaseException;


import com.sleepycat.je.LockMode;


import com.sleepycat.je.OperationStatus;


...


Cursor cursor = null;


try {


    cursor = myDatabase.openCursor(null, null);


    DatabaseEntry foundKey = new DatabaseEntry();


    DatabaseEntry foundData = new DatabaseEntry();


    // 通过cursor.getNex方法来遍历记录


while (cursor.getNext(foundKey, foundData, LockMode.DEFAULT) ==


        OperationStatus.SUCCESS) {


String keyString = new String(foundKey.getData(), "UTF-8");


        String dataString = new String(foundData.getData(), "UTF-8");


        System.out.println("Key | Data : " + keyString + " | " +


                       dataString + "");


    }


} catch (DatabaseException de) {


    System.err.println("Error accessing database." + de);


} finally {


    // 使用后必须关闭游标


    cursor.close();


}


使用示例二:


package je.gettingStarted;


import com.sleepycat.je.Cursor;


import com.sleepycat.je.Database;


import com.sleepycat.je.DatabaseEntry;


import com.sleepycat.je.DatabaseException;


import com.sleepycat.je.LockMode;


import com.sleepycat.je.OperationStatus;


...


Cursor cursor = null;


try {


    ...


    // Open the cursor.


    cursor = myDatabase.openCursor(null, null);


    DatabaseEntry foundKey = new DatabaseEntry();


    DatabaseEntry foundData = new DatabaseEntry();


    // 使用cursor.getPrev方法来遍历游标获取数据


   while (cursor.getPrev(foundKey, foundData, LockMode.DEFAULT)


       == OperationStatus.SUCCESS) {


        String theKey = new String(foundKey.getData(), "UTF-8");


        String theData = new String(foundData.getData(), "UTF-8");


        System.out.println("Key | Data : " + theKey + " | " + theData + "");


    }


} catch (DatabaseException de) {


    System.err.println("Error accessing database." + de);


} finally {


    // 使用后必须关闭游标


    cursor.close();


}


l 搜索数据


你可以通过游标方式搜索你的database记录,你也可以通过一个key来搜索你的记录,同样的你也可以通过key和value组合在一起来搜索记录。如果查询失败,则游标会返回OperationStatus.NOTFOUND。


游标支持都检索方法如下:


1) Cursor.getSearchKey()


通过key的方式检索,使用后游标指针将移动到跟当前key匹配的第一项。


2) Cursor.getSearchKeyRange()


把游标移动到大于或等于查询的key的第一个匹配key,大小比较是通过你设置的比较器来完成的,如果没有设置则使用默认的比较器。


3) Cursor.getSearchBoth()


通过key和value方式检索,然后把游标指针移动到与查询匹配的第一项。


4) Cursor.getSearchBothRange()


把游标移动到所有的匹配key和大于或等于指定的data的第一项。


比如说database存在如下的key/value记录,,大小比较是通过你设置的比较器来完成的,如果没有设置则使用默认的比较器。


假设你的database存在如下的记录。


               Alabama/Athens
               Alabama/Florence
               Alaska/Anchorage
               Alaska/Fairbanks
                Arizona/Avondale
               Arizona/Florence
然后查询


查询的key


查询的data


游标指向


Alaska


Fa


Alaska/Fairbanks


Arizona


Fl


Arizona/Florence


Alaska


An


Alaska/Anchorage


使用示例:


package je.gettingStarted;


import com.sleepycat.je.Cursor;


import com.sleepycat.je.Database;


import com.sleepycat.je.DatabaseEntry;


import com.sleepycat.je.DatabaseException;


import com.sleepycat.je.LockMode;


import com.sleepycat.je.OperationStatus;


...


String searchKey = "Alaska";


String searchData = "Fa";


Cursor cursor = null;


try {


    ...


    cursor = myDatabase.openCursor(null, null);


    DatabaseEntry theKey =


         new DatabaseEntry(searchKey.getBytes("UTF-8"));


    DatabaseEntry theData =


         new DatabaseEntry(searchData.getBytes("UTF-8"));


    cursor = myDatabase.openCursor(null, null);


OperationStatus retVal = cursor.getSearchBothRange(theKey,


theData, LockMode.DEFAULT);


    if (retVal == OperationStatus.NOTFOUND) {


        System.out.println(searchKey + "/" + searchData +


                           " not matched in database " +


                           myDatabase.getDatabaseName());


    } else {


        String foundKey = new String(theKey.getData(), "UTF-8");


        String foundData = new String(theData.getData(), "UTF-8");


        System.out.println("Found record " + foundKey + "/" + foundData +


                           "for search key/data: " + searchKey +


                           "/" + searchData);


    }


} catch (Exception e) {


    // Exception handling goes here


} finally {


   cursor.close();


}


l 使用游标来定位多重记录


如果你的库支持多重记录,你可以使用游标来遍历一个key下的多个data.


1) Cursor.getNext(), Cursor.getPrev()


获取上一条记录或下一条记录


2) Cursor.getSearchBothRange()


用语定位到满足指定data的第一条记录。


3) Cursor.getNextNoDup(), Cursor.getPrevNoDup()


跳到上一个key的最后一个data或下一个key的第一个data,忽略 当前key多重记录的存在。


4) Cursor.getNextDup(), Cursor.getPrevDup()


在当前key中把指针移动到前一个data或后一个data.


5) Cursor.count()


获取当前key下的data总数。


使用示例:


package je.gettingStarted;


import com.sleepycat.je.Cursor;


import com.sleepycat.je.Database;


import com.sleepycat.je.DatabaseEntry;


import com.sleepycat.je.DatabaseException;


import com.sleepycat.je.LockMode;


import com.sleepycat.je.OperationStatus;


...


Cursor cursor = null;


try {


    ...


    // Create DatabaseEntry objects


    // searchKey is some String.


    DatabaseEntry theKey = new DatabaseEntry(searchKey.getBytes("UTF-8"));


    DatabaseEntry theData = new DatabaseEntry();


    cursor = myDatabase.openCursor(null, null);


OperationStatus retVal = cursor.getSearchKey(theKey,


theData, LockMode.DEFAULT);


    // 如果count超过一个,则遍历


    if (cursor.count() > 1) {


        while (retVal == OperationStatus.SUCCESS) {


            String keyString = new String(theKey.getData(), "UTF-8");


            String dataString = new String(theData.getData(), "UTF-8");


            System.out.println("Key | Data : " + keyString + " | " +


                               dataString + "");


            retVal = cursor.getNextDup(theKey, theData, LockMode.DEFAULT);


        }


    }


} catch (Exception e) {


    // Exception handling goes here


} finally {


   // Make sure to close the cursor


   cursor.close();


}


l 通过游标来添加数据


你可以通过游标来向database里添加数据


你可以使用如下方法来向database里添加数据


1) Cursor.put()


如果database不存在key,则添加,如果database存在key但允许多重记录,则可以通过比较器在适当的位置插入数据,如果key已存在且不支持多重记录,则替换原有的数据。


2) Cursor.putNoDupData()


如果存在相同的key和data则返回OperationStatus.KEYEXIST.


如果不存在key则添加数据。


3) Cursor.putNoOverwrite()


如果存在相同的key在database里则返OperationStatus.KEYEXIS,


如果不存在key则添加数据。


package je.gettingStarted;


import com.sleepycat.je.Cursor;


import com.sleepycat.je.Database;


import com.sleepycat.je.DatabaseEntry;


import com.sleepycat.je.OperationStatus;


...


String key1str = "My first string";


String data1str = "My first data";


String key2str = "My second string";


String data2str = "My second data";


String data3str = "My third data";


Cursor cursor = null;


try {


    ...


    DatabaseEntry key1 = new DatabaseEntry(key1str.getBytes("UTF-8"));


    DatabaseEntry data1 = new DatabaseEntry(data1str.getBytes("UTF-8"));


    DatabaseEntry key2 = new DatabaseEntry(key2str.getBytes("UTF-8"));


    DatabaseEntry data2 = new DatabaseEntry(data2str.getBytes("UTF-8"));


    DatabaseEntry data3 = new DatabaseEntry(data3str.getBytes("UTF-8"));


    cursor = myDatabase.openCursor(null, null);


OperationStatus retVal = cursor.put(key1, data1); // 添加成功


    retVal = cursor.put(key2, data2); // 添加成功


    retVal = cursor.put(key2, data3); // 如果允许多重记录则添加成功                                                                                      //否则添加失败


} catch (Exception e) {


    // Exception handling goes here


} finally {


   // Make sure to close the cursor


   cursor.close();


}


l 使用游标来删除记录


你可以通过调用Cursor.delete().方法来删除当前游标所指向的记录。删除后如果没有移动过指针这个时候调用Cursor.getCurrent()还是可以得到当前值的,但移动以后就不可以了。如果没有重设指针,对同一个位置多次调用删除方法,会返回OperationStatus.KEYEMPTY状态。


使用示例:


package je.gettingStarted;


import com.sleepycat.je.Cursor;


import com.sleepycat.je.Database;


import com.sleepycat.je.DatabaseEntry;


import com.sleepycat.je.LockMode;


import com.sleepycat.je.OperationStatus;


...


Cursor cursor = null;


try {


    ...


    DatabaseEntry theKey = new DatabaseEntry(searchKey.getBytes("UTF-8"));


    DatabaseEntry theData = new DatabaseEntry();


    cursor = myDatabase.openCursor(null, null);


    OperationStatus retVal = cursor.getSearchKey(theKey, theData,                                        LockMode.DEFAULT);


    //如果date不是多重记录.


    if (cursor.count() == 1) {


            System.out.println("Deleting " +


                               new String(theKey.getData(), "UTF-8") +


                               "|" +


                               new String(theData.getData(), "UTF-8"));


            cursor.delete();//删除当前记录


    }


} catch (Exception e) {


    // Exception handling goes here


} finally {


   // Make sure to close the cursor


   cursor.close();


}


l 修改当前游标所在位置的值


可以通过Cursor.putCurrent()方法来修改,这个方法只有一个参数就是将要修改的值。这个方法不能用在多重记录。


使用示例:


import com.sleepycat.je.Cursor;


import com.sleepycat.je.Database;


import com.sleepycat.je.DatabaseEntry;


import com.sleepycat.je.LockMode;


import com.sleepycat.je.OperationStatus;


...


Cursor cursor = null;


try {


    ...


    DatabaseEntry theKey = new DatabaseEntry(searchKey.getBytes("UTF-8"));


    DatabaseEntry theData = new DatabaseEntry();


    cursor = myDatabase.openCursor(null, null);


    OperationStatus retVal = cursor.getSearchKey(theKey, theData,


LockMode.DEFAULT);


    //将要被替换的值


    String replaceStr = "My replacement string";


    DatabaseEntry replacementData =


        new DatabaseEntry(replaceStr.getBytes("UTF-8"));


    cursor.putCurrent(replacementData);//把当前位置用新值替换


} catch (Exception e) {


    // Exception handling goes here


} finally {


   // Make sure to close the cursor


   cursor.close();


}
0 0
原创粉丝点击