598 lines
21 KiB
HTML
598 lines
21 KiB
HTML
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
|
||
<html xmlns="http://www.w3.org/1999/xhtml">
|
||
<head>
|
||
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
|
||
<title>Getting Records Using the Cursor</title>
|
||
<link rel="stylesheet" href="gettingStarted.css" type="text/css" />
|
||
<meta name="generator" content="DocBook XSL Stylesheets V1.62.4" />
|
||
<link rel="home" href="index.html" title="Getting Started with Berkeley DB" />
|
||
<link rel="up" href="Cursors.html" title="Chapter 9. Using Cursors" />
|
||
<link rel="previous" href="Cursors.html" title="Chapter 9. Using Cursors" />
|
||
<link rel="next" href="PutEntryWCursor.html" title="Putting Records Using Cursors" />
|
||
</head>
|
||
<body>
|
||
<div class="navheader">
|
||
<table width="100%" summary="Navigation header">
|
||
<tr>
|
||
<th colspan="3" align="center">Getting Records Using the Cursor</th>
|
||
</tr>
|
||
<tr>
|
||
<td width="20%" align="left"><a accesskey="p" href="Cursors.html">Prev</a> </td>
|
||
<th width="60%" align="center">Chapter 9. Using Cursors</th>
|
||
<td width="20%" align="right"> <a accesskey="n" href="PutEntryWCursor.html">Next</a></td>
|
||
</tr>
|
||
</table>
|
||
<hr />
|
||
</div>
|
||
<div class="sect1" lang="en" xml:lang="en">
|
||
<div class="titlepage">
|
||
<div>
|
||
<div>
|
||
<h2 class="title" style="clear: both"><a id="Positioning"></a>Getting Records Using the Cursor</h2>
|
||
</div>
|
||
</div>
|
||
<div></div>
|
||
</div>
|
||
<p>
|
||
To iterate over database records, from the first record to
|
||
the last, simply open the cursor and then use the
|
||
<tt class="methodname">Cursor.getNext()</tt>
|
||
|
||
|
||
method.
|
||
|
||
For example:
|
||
</p>
|
||
<a id="java_cursor3"></a>
|
||
<pre class="programlisting">package db.GettingStarted;
|
||
|
||
import com.sleepycat.db.Database;
|
||
import com.sleepycat.db.DatabaseEntry;
|
||
import com.sleepycat.db.DatabaseException;
|
||
import com.sleepycat.db.Cursor;
|
||
import com.sleepycat.db.LockMode;
|
||
import com.sleepycat.db.OperationStatus;
|
||
|
||
...
|
||
|
||
Cursor cursor = null;
|
||
try {
|
||
...
|
||
Database myDatabase = null;
|
||
// Database open omitted for brevity
|
||
...
|
||
|
||
// Open the cursor.
|
||
cursor = myDatabase.openCursor(null, null);
|
||
|
||
// Cursors need a pair of DatabaseEntry objects to operate. These hold
|
||
// the key and data found at any given position in the database.
|
||
DatabaseEntry foundKey = new DatabaseEntry();
|
||
DatabaseEntry foundData = new DatabaseEntry();
|
||
|
||
// To iterate, just call getNext() until the last database record has been
|
||
// read. All cursor operations return an OperationStatus, so just read
|
||
// until we no longer see OperationStatus.SUCCESS
|
||
while (cursor.getNext(foundKey, foundData, LockMode.DEFAULT) ==
|
||
OperationStatus.SUCCESS) {
|
||
// getData() on the DatabaseEntry objects returns the byte array
|
||
// held by that object. We use this to get a String value. If the
|
||
// DatabaseEntry held a byte array representation of some other data
|
||
// type (such as a complex object) then this operation would look
|
||
// considerably different.
|
||
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 {
|
||
// Cursors must be closed.
|
||
cursor.close();
|
||
}</pre>
|
||
<p>
|
||
To iterate over the database from the last record to the first,
|
||
instantiate the cursor, and then
|
||
use <tt class="methodname">Cursor.getPrev()</tt> until you read the first record in
|
||
the database. For example:
|
||
</p>
|
||
<a id="java_cursor4"></a>
|
||
<pre class="programlisting">package db.GettingStarted;
|
||
|
||
import com.sleepycat.db.Cursor;
|
||
import com.sleepycat.db.Database;
|
||
import com.sleepycat.db.DatabaseEntry;
|
||
import com.sleepycat.db.DatabaseException;
|
||
import com.sleepycat.db.LockMode;
|
||
import com.sleepycat.db.OperationStatus;
|
||
|
||
...
|
||
|
||
Cursor cursor = null;
|
||
Database myDatabase = null;
|
||
try {
|
||
...
|
||
// Database open omitted for brevity
|
||
...
|
||
|
||
// Open the cursor.
|
||
cursor = myDatabase.openCursor(null, null);
|
||
|
||
// Get the DatabaseEntry objects that the cursor will use.
|
||
DatabaseEntry foundKey = new DatabaseEntry();
|
||
DatabaseEntry foundData = new DatabaseEntry();
|
||
|
||
// Iterate from the last record to the first in the database
|
||
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 {
|
||
// Cursors must be closed.
|
||
cursor.close();
|
||
}</pre>
|
||
<div class="sect2" lang="en" xml:lang="en">
|
||
<div class="titlepage">
|
||
<div>
|
||
<div>
|
||
<h3 class="title"><a id="cursorsearch"></a>Searching for Records</h3>
|
||
</div>
|
||
</div>
|
||
<div></div>
|
||
</div>
|
||
<p>
|
||
You can use cursors to search for database records. You can search based
|
||
on just a key, or you can search based on both the key and the data.
|
||
You can also perform partial matches if your database supports sorted
|
||
duplicate sets. In all cases, the key and data parameters of these
|
||
methods are filled with the key and data values of the database record
|
||
to which the cursor is positioned as a result of the search.
|
||
</p>
|
||
<p>
|
||
Also, if the search fails, then cursor's state is left unchanged
|
||
and
|
||
<tt class="literal">OperationStatus.NOTFOUND</tt>
|
||
|
||
is returned.
|
||
|
||
|
||
</p>
|
||
<p>
|
||
The following <tt class="classname">Cursor</tt> methods allow you to
|
||
perform database searches:
|
||
</p>
|
||
<div class="itemizedlist">
|
||
<ul type="disc">
|
||
<li>
|
||
<p>
|
||
<tt class="methodname">Cursor.getSearchKey()</tt>
|
||
|
||
</p>
|
||
<p>
|
||
Moves the cursor to the first record in the database with
|
||
the specified key.
|
||
</p>
|
||
</li>
|
||
<li>
|
||
<p>
|
||
<tt class="methodname">Cursor.getSearchKeyRange()</tt>
|
||
|
||
</p>
|
||
<p>
|
||
<span>Identical to
|
||
|
||
<tt class="methodname">Cursor.getSearchKey()</tt>
|
||
unless you are using the BTree access. In this case, the cursor
|
||
moves</span>
|
||
|
||
|
||
to the first record in the database whose
|
||
key is greater than or equal to the specified key. This comparison
|
||
is determined by the
|
||
<span>comparator</span>
|
||
|
||
that you provide for the database. If no
|
||
<span>comparator</span>
|
||
|
||
is provided, then the default
|
||
|
||
lexicographical sorting is used.
|
||
</p>
|
||
<p>
|
||
For example, suppose you have database records that use the
|
||
following
|
||
<span>Strings</span>
|
||
|
||
as keys:
|
||
</p>
|
||
<pre class="programlisting">Alabama
|
||
Alaska
|
||
Arizona</pre>
|
||
<p>
|
||
Then providing a search key of <tt class="literal">Alaska</tt> moves the
|
||
cursor to the second key noted above. Providing a key of
|
||
<tt class="literal">Al</tt> moves the cursor to the first key (<tt class="literal">Alabama</tt>), providing
|
||
a search key of <tt class="literal">Alas</tt> moves the cursor to the second key
|
||
(<tt class="literal">Alaska</tt>), and providing a key of <tt class="literal">Ar</tt> moves the
|
||
cursor to the last key (<tt class="literal">Arizona</tt>).
|
||
</p>
|
||
</li>
|
||
<li>
|
||
<p>
|
||
<tt class="methodname">Cursor.getSearchBoth()</tt>
|
||
|
||
</p>
|
||
<p>
|
||
Moves the cursor to the first record in the database that uses
|
||
the specified key and data.
|
||
</p>
|
||
</li>
|
||
<li>
|
||
<p>
|
||
<tt class="methodname">Cursor.getSearchBothRange()</tt>
|
||
|
||
</p>
|
||
<p>
|
||
Moves the cursor to the first record in the database whose key matches the specified
|
||
key and whose data is
|
||
greater than or equal to the specified data. If the database supports
|
||
duplicate records, then on matching the key, the cursor is moved to
|
||
the duplicate record with the smallest data that is greater than or
|
||
equal to the specified data.
|
||
</p>
|
||
<p>
|
||
For example,
|
||
|
||
<span>suppose your database uses BTree
|
||
and it has </span>
|
||
database records that use the following key/data pairs:
|
||
</p>
|
||
<pre class="programlisting">Alabama/Athens
|
||
Alabama/Florence
|
||
Alaska/Anchorage
|
||
Alaska/Fairbanks
|
||
Arizona/Avondale
|
||
Arizona/Florence </pre>
|
||
<p>then providing:</p>
|
||
<div class="informaltable">
|
||
<table border="1" width="80%">
|
||
<colgroup>
|
||
<col />
|
||
<col />
|
||
<col />
|
||
</colgroup>
|
||
<thead>
|
||
<tr>
|
||
<th>a search key of ...</th>
|
||
<th>and a search data of ...</th>
|
||
<th>moves the cursor to ...</th>
|
||
</tr>
|
||
</thead>
|
||
<tbody>
|
||
<tr>
|
||
<td>Alaska</td>
|
||
<td>Fa</td>
|
||
<td>Alaska/Fairbanks</td>
|
||
</tr>
|
||
<tr>
|
||
<td>Arizona</td>
|
||
<td>Fl</td>
|
||
<td>Arizona/Florence</td>
|
||
</tr>
|
||
<tr>
|
||
<td>Alaska</td>
|
||
<td>An</td>
|
||
<td>Alaska/Anchorage</td>
|
||
</tr>
|
||
</tbody>
|
||
</table>
|
||
</div>
|
||
</li>
|
||
</ul>
|
||
</div>
|
||
<p>
|
||
For example, assuming a database containing sorted duplicate records of
|
||
U.S. States/U.S Cities key/data pairs (both as
|
||
<span>Strings),</span>
|
||
|
||
then the following code fragment can be used to position the cursor
|
||
to any record in the database and print its key/data values:
|
||
|
||
</p>
|
||
<a id="java_cursor5"></a>
|
||
<pre class="programlisting">package db.GettingStarted;
|
||
|
||
import com.sleepycat.db.Cursor;
|
||
import com.sleepycat.db.Database;
|
||
import com.sleepycat.db.DatabaseEntry;
|
||
import com.sleepycat.db.DatabaseException;
|
||
import com.sleepycat.db.LockMode;
|
||
import com.sleepycat.db.OperationStatus;
|
||
|
||
...
|
||
|
||
// For this example, hard code the search key and data
|
||
String searchKey = "Alaska";
|
||
String searchData = "Fa";
|
||
|
||
Cursor cursor = null;
|
||
Database myDatabase = null;
|
||
try {
|
||
...
|
||
// Database open omitted for brevity
|
||
...
|
||
|
||
// Open the cursor.
|
||
cursor = myDatabase.openCursor(null, null);
|
||
|
||
DatabaseEntry theKey =
|
||
new DatabaseEntry(searchKey.getBytes("UTF-8"));
|
||
DatabaseEntry theData =
|
||
new DatabaseEntry(searchData.getBytes("UTF-8"));
|
||
|
||
// Open a cursor using a database handle
|
||
cursor = myDatabase.openCursor(null, null);
|
||
|
||
// Perform the search
|
||
OperationStatus retVal = cursor.getSearchBothRange(theKey, theData,
|
||
LockMode.DEFAULT);
|
||
// NOTFOUND is returned if a record cannot be found whose key
|
||
// matches the search key AND whose data begins with the search data.
|
||
if (retVal == OperationStatus.NOTFOUND) {
|
||
System.out.println(searchKey + "/" + searchData +
|
||
" not matched in database " +
|
||
myDatabase.getDatabaseName());
|
||
} else {
|
||
// Upon completing a search, the key and data DatabaseEntry
|
||
// parameters for getSearchBothRange() are populated with the
|
||
// key/data values of the found record.
|
||
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 {
|
||
// Make sure to close the cursor
|
||
cursor.close();
|
||
}</pre>
|
||
</div>
|
||
<div class="sect2" lang="en" xml:lang="en">
|
||
<div class="titlepage">
|
||
<div>
|
||
<div>
|
||
<h3 class="title"><a id="getdups"></a>Working with Duplicate Records</h3>
|
||
</div>
|
||
</div>
|
||
<div></div>
|
||
</div>
|
||
<p>
|
||
A record is a duplicate of another record if the two records share the
|
||
same key. For duplicate records, only the data portion of the record is unique.
|
||
</p>
|
||
<p>
|
||
Duplicate records are supported only for the BTree or Hash access methods.
|
||
For information on configuring your database to use duplicate records,
|
||
see <a href="btree.html#duplicateRecords">Allowing Duplicate Records</a>.
|
||
</p>
|
||
<p>
|
||
If your database supports duplicate records, then it can potentially
|
||
contain multiple records that share the same key.
|
||
|
||
|
||
|
||
<span>By default, normal database
|
||
get operations will only return the first such record in a set
|
||
of duplicate records. Typically, subsequent duplicate records are
|
||
accessed using a cursor.
|
||
</span>
|
||
|
||
The following
|
||
<span><tt class="methodname">Cursor</tt> methods</span>
|
||
|
||
|
||
are interesting when working with databases that support duplicate records:
|
||
</p>
|
||
<div class="itemizedlist">
|
||
<ul type="disc">
|
||
<li>
|
||
<p>
|
||
<span>
|
||
<tt class="methodname">Cursor.getNext()</tt>,
|
||
<tt class="methodname">Cursor.getPrev()</tt>
|
||
</span>
|
||
|
||
</p>
|
||
<p>
|
||
Shows the next/previous record in the database, regardless of
|
||
whether it is a duplicate of the current record. For an example of
|
||
using these methods, see <a href="Positioning.html">Getting Records Using the Cursor</a>.
|
||
</p>
|
||
</li>
|
||
<li>
|
||
<p>
|
||
<tt class="methodname">Cursor.getSearchBothRange()</tt>
|
||
|
||
</p>
|
||
<p>
|
||
Useful for seeking the cursor to a specific record, regardless of
|
||
whether it is a duplicate record. See <a href="Positioning.html#cursorsearch">Searching for Records</a> for more
|
||
information.
|
||
</p>
|
||
</li>
|
||
<li>
|
||
<p>
|
||
<span>
|
||
<tt class="methodname">Cursor.getNextNoDup()</tt>,
|
||
<tt class="methodname">Cursor.getPrevNoDup()</tt>
|
||
</span>
|
||
|
||
</p>
|
||
<p>
|
||
Gets the next/previous non-duplicate record in the database. This
|
||
allows you to skip over all the duplicates in a set of duplicate
|
||
records. If you call
|
||
<span><tt class="methodname">Cursor.getPrevNoDup()</tt>,</span>
|
||
|
||
then the cursor is positioned to the last record for the previous
|
||
key in the database. For example, if you have the following records
|
||
in your database:
|
||
</p>
|
||
<pre class="programlisting">Alabama/Athens
|
||
Alabama/Florence
|
||
Alaska/Anchorage
|
||
Alaska/Fairbanks
|
||
Arizona/Avondale
|
||
Arizona/Florence</pre>
|
||
<p>
|
||
and your cursor is positioned to <tt class="literal">Alaska/Fairbanks</tt>,
|
||
and you then call
|
||
<span><tt class="methodname">Cursor.getPrevNoDup()</tt>,</span>
|
||
|
||
then the cursor is positioned to Alabama/Florence. Similarly, if
|
||
you call
|
||
<span><tt class="methodname">Cursor.getNextNoDup()</tt>,</span>
|
||
|
||
|
||
then the cursor is positioned to the first record corresponding to
|
||
the next key in the database.
|
||
</p>
|
||
<p>
|
||
If there is no next/previous key in the database, then
|
||
<tt class="literal">OperationStatus.NOTFOUND</tt>
|
||
|
||
is returned, and the cursor is left unchanged.
|
||
</p>
|
||
</li>
|
||
<li>
|
||
<p>
|
||
|
||
|
||
</p>
|
||
<p>
|
||
|
||
Gets the
|
||
|
||
<span>next</span>
|
||
record that shares the current key. If the
|
||
cursor is positioned at the last record in the duplicate set and
|
||
you call
|
||
<span><tt class="methodname">Cursor.getNextDup()</tt>,</span>
|
||
|
||
|
||
then
|
||
<tt class="literal">OperationStatus.NOTFOUND</tt>
|
||
|
||
is returned and the cursor is left unchanged.
|
||
<span>
|
||
Likewise, if you call
|
||
<tt class="methodname">getPrevDup()</tt> and the
|
||
cursor is positioned at the first record in the duplicate set, then
|
||
<tt class="literal">OperationStatus.NOTFOUND</tt> is returned and the
|
||
cursor is left unchanged.
|
||
</span>
|
||
</p>
|
||
</li>
|
||
<li>
|
||
<p>
|
||
<tt class="methodname">Cursor.count()</tt>
|
||
</p>
|
||
<p>Returns the total number of records that share the current key.</p>
|
||
</li>
|
||
</ul>
|
||
</div>
|
||
<p>
|
||
For example, the following code fragment positions a cursor to a key
|
||
|
||
|
||
|
||
<span>and displays it and all its
|
||
duplicates.</span>
|
||
|
||
<span>Note that the following code fragment assumes that the database contains
|
||
only String objects for the keys and data.</span>
|
||
</p>
|
||
<a id="java_cursor6"></a>
|
||
<pre class="programlisting">package db.GettingStarted;
|
||
|
||
import com.sleepycat.db.Cursor;
|
||
import com.sleepycat.db.Database;
|
||
import com.sleepycat.db.DatabaseEntry;
|
||
import com.sleepycat.db.DatabaseException;
|
||
import com.sleepycat.db.LockMode;
|
||
import com.sleepycat.db.OperationStatus;
|
||
|
||
...
|
||
|
||
Cursor cursor = null;
|
||
Database myDatabase = null;
|
||
try {
|
||
...
|
||
// Database open omitted for brevity
|
||
...
|
||
|
||
// Create DatabaseEntry objects
|
||
// searchKey is some String.
|
||
DatabaseEntry theKey = new DatabaseEntry(searchKey.getBytes("UTF-8"));
|
||
DatabaseEntry theData = new DatabaseEntry();
|
||
|
||
// Open a cursor using a database handle
|
||
cursor = myDatabase.openCursor(null, null);
|
||
|
||
// Position the cursor
|
||
// Ignoring the return value for clarity
|
||
OperationStatus retVal = cursor.getSearchKey(theKey, theData,
|
||
LockMode.DEFAULT);
|
||
|
||
// Count the number of duplicates. If the count is greater than 1,
|
||
// print the duplicates.
|
||
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();
|
||
}</pre>
|
||
</div>
|
||
</div>
|
||
<div class="navfooter">
|
||
<hr />
|
||
<table width="100%" summary="Navigation footer">
|
||
<tr>
|
||
<td width="40%" align="left"><a accesskey="p" href="Cursors.html">Prev</a> </td>
|
||
<td width="20%" align="center">
|
||
<a accesskey="u" href="Cursors.html">Up</a>
|
||
</td>
|
||
<td width="40%" align="right"> <a accesskey="n" href="PutEntryWCursor.html">Next</a></td>
|
||
</tr>
|
||
<tr>
|
||
<td width="40%" align="left" valign="top">Chapter 9. Using Cursors </td>
|
||
<td width="20%" align="center">
|
||
<a accesskey="h" href="index.html">Home</a>
|
||
</td>
|
||
<td width="40%" align="right" valign="top"> Putting Records Using Cursors</td>
|
||
</tr>
|
||
</table>
|
||
</div>
|
||
</body>
|
||
</html>
|