如何按“值”的降序遍历 berkeley-db 数据库?
Posted
技术标签:
【中文标题】如何按“值”的降序遍历 berkeley-db 数据库?【英文标题】:How to traverse berkeley-db database in descending order of 'value'? 【发布时间】:2012-09-16 13:46:47 【问题描述】:我有一个 Berkeley-db 数据库,其中“键”和“值”都是整数类型。有没有办法按‘value’降序遍历数据库?
我正在使用 Berkeley-db je-5.0.58 API。我在其文档中使用的示例代码如下所示。
/*-
* See the file LICENSE for redistribution information.
*
* Copyright (c) 2004-2010 Oracle. All rights reserved.
*
*/
package je;
import java.io.File;
import com.sleepycat.bind.tuple.IntegerBinding;
import com.sleepycat.je.Cursor;
import com.sleepycat.je.Database;
import com.sleepycat.je.DatabaseConfig;
import com.sleepycat.je.DatabaseEntry;
import com.sleepycat.je.DatabaseException;
import com.sleepycat.je.Environment;
import com.sleepycat.je.EnvironmentConfig;
import com.sleepycat.je.LockMode;
import com.sleepycat.je.OperationStatus;
import com.sleepycat.je.Transaction;
/**
* SimpleExample creates a database environment, a database, and a database
* cursor, inserts and retrieves data.
*/
class SimpleExample
private static final int EXIT_SUCCESS = 0;
private static final int EXIT_FAILURE = 1;
private int numRecords; // num records to insert or retrieve
private int offset; // where we want to start inserting
private boolean doInsert; // if true, insert, else retrieve
private File envDir;
public SimpleExample(int numRecords,
boolean doInsert,
File envDir,
int offset)
this.numRecords = numRecords;
this.doInsert = doInsert;
this.envDir = envDir;
this.offset = offset;
/**
* Usage string
*/
public static void usage()
System.out.println("usage: java " +
"je.SimpleExample " +
"<dbEnvHomeDirectory> " +
"<insert|retrieve> <numRecords> [offset]");
System.exit(EXIT_FAILURE);
/**
* Main
*/
public static void main(String argv[])
if (argv.length < 2)
usage();
return;
File envHomeDirectory = new File(argv[0]);
boolean doInsertArg = false;
if (argv[1].equalsIgnoreCase("insert"))
doInsertArg = true;
else if (argv[1].equalsIgnoreCase("retrieve"))
doInsertArg = false;
else
usage();
int startOffset = 0;
int numRecordsVal = 0;
if (doInsertArg)
if (argv.length > 2)
numRecordsVal = Integer.parseInt(argv[2]);
else
usage();
return;
if (argv.length > 3)
startOffset = Integer.parseInt(argv[3]);
try
SimpleExample app = new SimpleExample(numRecordsVal,
doInsertArg,
envHomeDirectory,
startOffset);
app.run();
catch (DatabaseException e)
e.printStackTrace();
System.exit(EXIT_FAILURE);
System.exit(EXIT_SUCCESS);
/**
* Insert or retrieve data
*/
public void run() throws DatabaseException
/* Create a new, transactional database environment */
EnvironmentConfig envConfig = new EnvironmentConfig();
envConfig.setTransactional(true);
envConfig.setAllowCreate(true);
Environment exampleEnv = new Environment(envDir, envConfig);
/*
* Make a database within that environment
*
* Notice that we use an explicit transaction to
* perform this database open, and that we
* immediately commit the transaction once the
* database is opened. This is required if we
* want transactional support for the database.
* However, we could have used autocommit to
* perform the same thing by simply passing a
* null txn handle to openDatabase().
*/
Transaction txn = exampleEnv.beginTransaction(null, null);
DatabaseConfig dbConfig = new DatabaseConfig();
dbConfig.setTransactional(true);
dbConfig.setAllowCreate(true);
dbConfig.setSortedDuplicates(true);
Database exampleDb = exampleEnv.openDatabase(txn,
"simpleDb",
dbConfig);
txn.commit();
/*
* Insert or retrieve data. In our example, database records are
* integer pairs.
*/
/* DatabaseEntry represents the key and data of each record */
DatabaseEntry keyEntry = new DatabaseEntry();
DatabaseEntry dataEntry = new DatabaseEntry();
if (doInsert)
/* put some data in */
for (int i = offset; i < numRecords + offset; i++)
/*
* Note that autocommit mode, described in the Getting
* Started Guide, is an alternative to explicitly
* creating the transaction object.
*/
txn = exampleEnv.beginTransaction(null, null);
/* Use a binding to convert the int into a DatabaseEntry. */
IntegerBinding.intToEntry(i, keyEntry);
IntegerBinding.intToEntry(i+1, dataEntry);
OperationStatus status =
exampleDb.put(txn, keyEntry, dataEntry);
/*
* Note that put will throw a DatabaseException when
* error conditions are found such as deadlock.
* However, the status return conveys a variety of
* information. For example, the put might succeed,
* or it might not succeed if the record alread exists
* and the database was not configured for duplicate
* records.
*/
if (status != OperationStatus.SUCCESS)
throw new RuntimeException("Data insertion got status " +
status);
txn.commit();
else
/* retrieve the data */
Cursor cursor = exampleDb.openCursor(null, null);
while (cursor.getNext(keyEntry, dataEntry, LockMode.DEFAULT) ==
OperationStatus.SUCCESS)
System.out.println("key=" +
IntegerBinding.entryToInt(keyEntry) +
" data=" +
IntegerBinding.entryToInt(dataEntry));
cursor.close();
exampleDb.close();
exampleEnv.close();
【问题讨论】:
可以提供更多细节吗?您使用的是哪个 Berkeley-db Java API?你有一些示例代码吗? 请看上面,我已经更新了问题。 【参考方案1】:您可以使用custom comparator 和使用cursor 以降序遍历数据。
在java中你必须实现一个自定义的比较器:
编辑:
import java.util.Comparator;
import com.sleepycat.bind.tuple.IntegerBinding;
import com.sleepycat.je.DatabaseEntry;
public class IntegerSorter implements Comparator<byte[]>
@Override
public int compare(byte[] o1, byte[] o2)
return
IntegerBinding.entryToInt(new DatabaseEntry(o1)) -
IntegerBinding.entryToInt(new DatabaseEntry(o2));
(...)
dbConfig.setBtreeComparator(IntegerSorter.class);
(...)
【讨论】:
感谢您的及时回复。按照您的建议使用自定义比较器后,程序编译没有任何错误。但我在运行时遇到以下异常:线程“main”java.lang.IllegalArgumentException 中的异常:Btree 比较器无效。可能您没有为比较器实现零参数构造函数,或者找不到比较器类。我试图用谷歌搜索它,但找不到任何解决方案。 :( 整个数据库必须是使用比较器从头开始构建的。您无法构建/填充数据库,然后添加此比较器。 在编译之前我已经删除了所有以前的数据库和类文件,但它仍然给出了同样的错误。 是你类路径中的 IntegerSorter.class 吗? 谢谢。我解决了这个问题。问题不在于类路径,但我已将 IntegerSorter 声明为 SimpleExample 类的内部类。但输出按“键”的降序排列。有没有办法按“价值”的降序遍历?以上是关于如何按“值”的降序遍历 berkeley-db 数据库?的主要内容,如果未能解决你的问题,请参考以下文章