1<?xml version="1.0" encoding="UTF-8" standalone="no"?>
2<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
3<html xmlns="http://www.w3.org/1999/xhtml">
4  <head>
5    <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
6    <title>DPL Transaction Example</title>
7    <link rel="stylesheet" href="gettingStarted.css" type="text/css" />
8    <meta name="generator" content="DocBook XSL Stylesheets V1.73.2" />
9    <link rel="start" href="index.html" title="Getting Started with Berkeley DB Transaction Processing" />
10    <link rel="up" href="wrapup.html" title="Chapter 6. Summary and Examples" />
11    <link rel="prev" href="txnexample_java.html" title="Base API Transaction Example" />
12    <link rel="next" href="inmem_txnexample_java.html" title="Base API In-Memory Transaction Example" />
13  </head>
14  <body>
15    <div class="navheader">
16      <table width="100%" summary="Navigation header">
17        <tr>
18          <th colspan="3" align="center">DPL Transaction Example</th>
19        </tr>
20        <tr>
21          <td width="20%" align="left"><a accesskey="p" href="txnexample_java.html">Prev</a> </td>
22          <th width="60%" align="center">Chapter 6. Summary and Examples</th>
23          <td width="20%" align="right"> <a accesskey="n" href="inmem_txnexample_java.html">Next</a></td>
24        </tr>
25      </table>
26      <hr />
27    </div>
28    <div class="sect1" lang="en" xml:lang="en">
29      <div class="titlepage">
30        <div>
31          <div>
32            <h2 class="title" style="clear: both"><a id="txnexample_dpl"></a>DPL Transaction Example</h2>
33          </div>
34        </div>
35      </div>
36      <div class="toc">
37        <dl>
38          <dt>
39            <span class="sect2">
40              <a href="txnexample_dpl.html#txnguideexample_dpl">TxnGuide.java</a>
41            </span>
42          </dt>
43          <dt>
44            <span class="sect2">
45              <a href="txnexample_dpl.html#payloaddataentity">PayloadDataEntity.java</a>
46            </span>
47          </dt>
48          <dt>
49            <span class="sect2">
50              <a href="txnexample_dpl.html#storewriter">StoreWriter.java</a>
51            </span>
52          </dt>
53        </dl>
54      </div>
55      <p>
56        The following Java code provides a fully functional example of a
57        multi-threaded transactional DB application using the DPL. 
58        This example is nearly identical to the example provided in the
59        previous section, except that it uses an entity class and entity
60        store to manage its data.
61    </p>
62      <p>
63            As is the case with the previous examples, this example opens
64            an environment and then an entity store. It then creates 
65            5 threads, each of which writes 500 records to the database.
66            The primary key for these writes are based on pre-determined
67            integers, while the data is randomly generated data. 
68            This means that the actual data is arbitrary and therefore uninteresting; 
69            we picked it only because it requires minimum code to implement and therefore will 
70        stay out of the way of the main points of this example.
71    </p>
72      <p>
73        Each thread writes 10 records under a single transaction
74        before committing and writing another 10 (this is repeated 50
75        times). At the end of each transaction, but before committing, each
76        thread calls a function that uses a cursor to read every record in
77        the database. We do this in order to make some points about
78        database reads in a transactional environment.
79    </p>
80      <p>
81        Of course, each writer thread performs deadlock detection as
82        described in this manual. In addition, normal recovery is performed
83        when the environment is opened.
84    </p>
85      <p>
86        To implement this example, we need three classes:    
87    </p>
88      <div class="itemizedlist">
89        <ul type="disc">
90          <li>
91            <p>
92                <code class="literal">TxnGuide.java</code>
93            </p>
94            <p>
95                This is the main class for the application. It performs
96                environment and store management, spawns threads, and
97                creates the data that is placed in the database.  See <a class="xref" href="txnexample_dpl.html#txnguideexample_dpl" title="TxnGuide.java">TxnGuide.java</a> for implementation details.
98            </p>
99          </li>
100          <li>
101            <p>
102                <code class="literal">StoreWriter.java</code>
103            </p>
104            <p>
105                This class extends <code class="literal">java.lang.Thread</code>, and
106                as such it is our thread implementation.  It is responsible
107                for actually reading and writing store. It also
108                performs all of our transaction management.  See <a class="xref" href="txnexample_dpl.html#storewriter" title="StoreWriter.java">StoreWriter.java</a> for
109                implementation details.
110            </p>
111          </li>
112          <li>
113            <p>
114                <code class="literal">PayloadDataEntity.java</code>
115            </p>
116            <p>
117                This is an entity class used to encapsulate several data
118                fields.  See <a class="xref" href="txnexample_dpl.html#payloaddataentity" title="PayloadDataEntity.java">PayloadDataEntity.java</a> for
119                implementation details.
120            </p>
121          </li>
122        </ul>
123      </div>
124      <div class="sect2" lang="en" xml:lang="en">
125        <div class="titlepage">
126          <div>
127            <div>
128              <h3 class="title"><a id="txnguideexample_dpl"></a>TxnGuide.java</h3>
129            </div>
130          </div>
131        </div>
132        <p>
133            The main class in our example application is used to open and
134            close our environment and store. It also spawns all the
135            threads that we need. We start with the normal series
136            of Java package and import statements, followed by our class
137            declaration:
138        </p>
139        <pre class="programlisting">// File TxnGuideDPL.java
140
141package persist.txn;
142
143import com.sleepycat.db.DatabaseConfig;
144import com.sleepycat.db.DatabaseException;
145import com.sleepycat.db.DatabaseType;
146import com.sleepycat.db.LockDetectMode;
147
148import com.sleepycat.db.Environment;
149import com.sleepycat.db.EnvironmentConfig;
150
151import com.sleepycat.persist.EntityStore;
152import com.sleepycat.persist.StoreConfig;
153
154import java.io.File;
155import java.io.FileNotFoundException;
156
157public class TxnGuideDPL { </pre>
158        <p>
159    Next we declare our class' private data members. Mostly these are used
160    for constants such as the name of the database that we are opening and
161    the number of threads that we are spawning. However, we also declare
162    our environment and database handles here.
163</p>
164        <pre class="programlisting">    private static String myEnvPath = "./";
165    private static String storeName = "exampleStore";
166
167    // Handles
168    private static EntityStore myStore = null;
169                private static Environment myEnv = null;
170    private static final int NUMTHREADS = 5; </pre>
171        <p>
172    Next, we implement our <code class="function">usage()</code> method. This
173    application optionally accepts a single command line argument which is
174    used to identify the environment home directory.
175</p>
176        <pre class="programlisting">    private static void usage() {
177        System.out.println("TxnGuideDPL [-h &lt;env directory&gt;]");
178        System.exit(-1);
179    } </pre>
180        <p>
181    Now we implement our <code class="function">main()</code> method. This method
182    simply calls the methods to parse the command line arguments and open
183    the environment and store. It also creates and then joins the store writer
184    threads.
185</p>
186        <pre class="programlisting">    public static void main(String args[]) {
187        try {
188            // Parse the arguments list
189            parseArgs(args);
190            // Open the environment and store
191            openEnv();
192
193            // Start the threads
194            StoreWriter[] threadArray;
195            threadArray = new StoreWriter[NUMTHREADS];
196            for (int i = 0; i &lt; NUMTHREADS; i++) {
197                threadArray[i] = new StoreWriter(myEnv, myStore);
198                threadArray[i].start();
199            }
200
201            for (int i = 0; i &lt; NUMTHREADS; i++) {
202                threadArray[i].join();
203            }
204        } catch (Exception e) {
205            System.err.println("TxnGuideDPL: " + e.toString());
206            e.printStackTrace();
207        } finally {
208            closeEnv();
209        }
210        System.out.println("All done.");
211    } </pre>
212        <p>
213    Next we implement <code class="function">openEnv()</code>. This method is used
214    to open the environment and then an entity store in that environment. Along
215    the way, we make sure that every handle is free-threaded, and that the
216    transactional subsystem is correctly initialized. Because this is a
217    concurrent application, we also declare how we want deadlock detection
218    to be performed. In this case, we use DB's internal block detector
219    to determine whether a deadlock has occurred when a thread attempts to
220    acquire a lock. We also indicate that we want the deadlocked thread
221    with the <span class="emphasis"><em>youngest</em></span> lock to receive deadlock
222    notification.
223</p>
224        <p>
225    Notice that we also cause normal recovery to be run when we open the
226    environment. This is the standard and recommended thing to do whenever
227    you start up a transactional application.
228</p>
229        <p>
230    Finally, notice that we open the database such that it supports
231    uncommitted reads. We do this so that some cursor activity later in
232    this example can read uncommitted data.  If we did not do this, then
233    our <code class="methodname">countObjects()</code> method described later in
234    this example would cause our thread to self-deadlock. This is because
235    the cursor could not be opened to support uncommitted reads (that flag
236    on the cursor open would, in fact, be silently ignored).
237</p>
238        <pre class="programlisting">    private static void openEnv() throws DatabaseException {
239        System.out.println("opening env and store");
240
241        // Set up the environment.
242        EnvironmentConfig myEnvConfig = new EnvironmentConfig();
243        myEnvConfig.setAllowCreate(true);
244        myEnvConfig.setInitializeCache(true);
245        myEnvConfig.setInitializeLocking(true);
246        myEnvConfig.setInitializeLogging(true);
247        myEnvConfig.setRunRecovery(true);
248        myEnvConfig.setTransactional(true);
249        // EnvironmentConfig.setThreaded(true) is the default behavior 
250        // in Java, so we do not have to do anything to cause the
251        // environment handle to be free-threaded.
252
253        // Indicate that we want db to internally perform deadlock 
254        // detection. Also indicate that the transaction that has
255        // performed the least amount of write activity to
256        // receive the deadlock notification, if any.
257        myEnvConfig.setLockDetectMode(LockDetectMode.MINWRITE);
258
259        // Set up the entity store
260        StoreConfig myStoreConfig = new StoreConfig();
261        myStoreConfig.setAllowCreate(true);
262        myStoreConfig.setTransactional(true);
263
264        // Need a DatabaseConfig object so as to set uncommitted read
265        // support.
266        DatabaseConfig myDbConfig = new DatabaseConfig();
267        myDbConfig.setType(DatabaseType.BTREE);
268        myDbConfig.setAllowCreate(true);
269        myDbConfig.setTransactional(true);
270        myDbConfig.setReadUncommitted(true);
271
272        try {
273            // Open the environment
274            myEnv = new Environment(new File(myEnvPath),    // Env home
275                                    myEnvConfig);
276
277            // Open the store
278            myStore = new EntityStore(myEnv, storeName, myStoreConfig);
279
280            // Set the DatabaseConfig object, so that the underlying
281            // database is configured for uncommitted reads.
282            myStore.setPrimaryConfig(PayloadDataEntity.class, myDbConfig);
283        } catch (FileNotFoundException fnfe) {
284            System.err.println("openEnv: " + fnfe.toString());
285            System.exit(-1);
286        }
287    } </pre>
288        <p>
289    Finally, we implement the methods used to close our environment and
290    databases, parse the command line arguments, and provide our class
291    constructor. This is fairly standard code and it is mostly
292    uninteresting from the perspective of this manual. We include it here
293    purely for the purpose of completeness.
294</p>
295        <pre class="programlisting">    private static void closeEnv() {
296        System.out.println("Closing env and store");
297        if (myStore != null ) {
298            try {
299                myStore.close();
300            } catch (DatabaseException e) {
301                System.err.println("closeEnv: myStore: " +
302                    e.toString());
303                e.printStackTrace();
304            }
305        }
306
307        if (myEnv != null ) {
308            try {
309                myEnv.close();
310            } catch (DatabaseException e) {
311                System.err.println("closeEnv: " + e.toString());
312                e.printStackTrace();
313            }
314        }
315    }
316
317    private TxnGuideDPL() {}
318
319    private static void parseArgs(String args[]) {
320        int nArgs = args.length;
321        for(int i = 0; i &lt; args.length; ++i) {
322            if (args[i].startsWith("-")) {
323                switch(args[i].charAt(1)) {
324                    case 'h':
325                        if (i &lt; nArgs - 1) {
326                            myEnvPath = new String(args[++i]);
327                        }
328                    break;
329                    default:
330                        usage();
331                }
332            }
333        }
334    }
335} </pre>
336      </div>
337      <div class="sect2" lang="en" xml:lang="en">
338        <div class="titlepage">
339          <div>
340            <div>
341              <h3 class="title"><a id="payloaddataentity"></a>PayloadDataEntity.java</h3>
342            </div>
343          </div>
344        </div>
345        <p>
346    Before we show the implementation of the store writer thread, we
347    need to show the class that we will be placing into the store. This
348    class is fairly minimal. It simply allows you to store and retrieve an
349    <code class="literal">int</code>, a <code class="literal">String</code>, and a
350    <code class="literal">double</code>.  The <code class="literal">int</code> is our primary key.
351</p>
352        <pre class="programlisting">package persist.txn;
353import com.sleepycat.persist.model.Entity;
354import com.sleepycat.persist.model.PrimaryKey;
355import com.sleepycat.persist.model.SecondaryKey;
356import static com.sleepycat.persist.model.Relationship.*;
357
358@Entity
359public class PayloadDataEntity {
360    @PrimaryKey
361    private int oID;
362
363    @SecondaryKey(relate=MANY_TO_ONE)
364    private String threadName;
365
366    private double doubleData;
367
368    PayloadDataEntity() {}
369
370    public double getDoubleData() { return doubleData; }
371    public int getID() { return oID; }
372    public String getThreadName() { return threadName; }
373
374    public void setDoubleData(double dd) { doubleData = dd; }
375    public void setID(int id) { oID = id; }
376    public void setThreadName(String tn) { threadName = tn; }
377} </pre>
378      </div>
379      <div class="sect2" lang="en" xml:lang="en">
380        <div class="titlepage">
381          <div>
382            <div>
383              <h3 class="title"><a id="storewriter"></a>StoreWriter.java</h3>
384            </div>
385          </div>
386        </div>
387        <p>
388            <code class="literal">StoreWriter.java</code> provides the implementation
389            for our entity store writer thread. It is responsible for: 
390        </p>
391        <div class="itemizedlist">
392          <ul type="disc">
393            <li>
394              <p>
395                    All transaction management.
396                </p>
397            </li>
398            <li>
399              <p>
400                    Responding to deadlock exceptions.
401                </p>
402            </li>
403            <li>
404              <p>
405                    Providing data to be stored in the entity store.
406                </p>
407            </li>
408            <li>
409              <p>
410                    Writing the data to the store.
411                </p>
412            </li>
413          </ul>
414        </div>
415        <p>
416                In order to show off some of the ACID properties provided
417                by DB's transactional support,
418                <code class="literal">StoreWriter.java</code> does some things in a less
419                efficient way than you would probably decide to use in a
420                true production application. First, it groups 10 database
421                writes together in a single transaction when you could just
422                as easily perform one write for each transaction. If you
423                did this, you could use auto commit for the individual
424                database writes, which means your code would be slightly
425                simpler and you would run a <span class="emphasis"><em>much</em></span>
426                smaller chance of encountering blocked and deadlocked
427                operations. However, by doing things this way, we are able
428                to show transactional atomicity, as well as deadlock
429                handling.
430            </p>
431        <p>
432                To begin, we provide the usual package and import statements, and we declare our class:
433            </p>
434        <pre class="programlisting">package persist.txn;
435
436import com.sleepycat.db.CursorConfig;
437import com.sleepycat.db.DatabaseException;
438import com.sleepycat.db.DeadlockException;
439import com.sleepycat.db.Environment;
440import com.sleepycat.db.Transaction;
441
442import com.sleepycat.persist.EntityCursor;
443import com.sleepycat.persist.EntityStore;
444import com.sleepycat.persist.PrimaryIndex;
445
446import java.util.Iterator;
447import java.util.Random;
448import java.io.UnsupportedEncodingException;
449
450public class StoreWriter extends Thread
451{ </pre>
452        <p>
453    Next we declare our private data members. Notice that we get handles
454    for the environment and the entity store.  The random number generator 
455    that we instantiate is used
456    to generate unique data for storage in the database.  Finally, the
457    <code class="literal">MAX_RETRY</code> variable is used to define how many times
458    we will retry a transaction in the face of a deadlock. 
459</p>
460        <pre class="programlisting">    private EntityStore myStore = null;
461    private Environment myEnv = null;
462    private PrimaryIndex&lt;Integer,PayloadDataEntity&gt; pdIndex;
463    private Random generator = new Random();
464    private boolean passTxn = false;
465
466    private static final int MAX_RETRY = 20; </pre>
467        <p>
468        Next we implement our class constructor. The most interesting thing about our constructor is
469        that we use it to obtain our entity class's primary index.
470    </p>
471        <pre class="programlisting">    // Constructor. Get our handles from here
472    StoreWriter(Environment env, EntityStore store)
473
474        throws DatabaseException {
475        myStore = store;
476        myEnv = env;
477
478        // Open the data accessor. This is used to store persistent
479        // objects.
480        pdIndex = myStore.getPrimaryIndex(Integer.class,
481                    PayloadDataEntity.class);
482    } </pre>
483        <p>
484    Now we implement our thread's <code class="methodname">run()</code> method.
485    This is the method that is run when <code class="classname">StoreWriter</code>
486    threads are started in the main program (see <a class="xref" href="txnexample_dpl.html#txnguideexample_dpl" title="TxnGuide.java">TxnGuide.java</a>).
487</p>
488        <pre class="programlisting">    // Thread method that writes a series of records
489    // to the database using transaction protection.
490    // Deadlock handling is demonstrated here.
491    public void run () { </pre>
492        <p>
493    The first thing we do is get a <code class="literal">null</code> transaction
494    handle before going into our main loop. We also begin the top transaction loop here that causes our application to
495    perform 50 transactions.
496</p>
497        <pre class="programlisting">        Transaction txn = null;
498
499        // Perform 50 transactions
500        for (int i=0; i&lt;50; i++) { </pre>
501        <p>
502    Next we declare a <code class="literal">retry</code> variable. This is used to
503    determine whether a deadlock should result in our retrying the
504    operation. We also declare a  <code class="literal">retry_count</code> variable
505    that is used to make sure we do not retry a transaction forever in the
506    unlikely event that the thread is unable to ever get a necessary lock.
507    (The only thing that might cause this is if some other thread dies
508    while holding an important lock. This is the only code that we have to
509    guard against that because the simplicity of this application makes it
510    highly unlikely that it will ever occur.)
511</p>
512        <pre class="programlisting">           boolean retry = true;
513           int retry_count = 0;
514           // while loop is used for deadlock retries
515           while (retry) { </pre>
516        <p>
517    Now we go into the <code class="literal">try</code> block that we use for
518    deadlock detection. We also begin our transaction here.
519</p>
520        <pre class="programlisting">                // try block used for deadlock detection and
521                // general exception handling
522                try {
523
524                    // Get a transaction
525                    txn = myEnv.beginTransaction(null, null); </pre>
526        <p>
527        Now we write 10 objects under the transaction that we have just begun. 
528        By combining multiple writes together under a single transaction,
529        we increase the likelihood that a deadlock will occur. Normally,
530        you want to reduce the potential for a deadlock and in this case
531        the way to do that is to perform a single write per transaction. In
532        other words, we <span class="emphasis"><em>should</em></span> be using auto commit to
533        write to our database for this workload.
534    </p>
535        <p>
536        However, we want to show deadlock handling and by performing
537        multiple writes per transaction we can actually observe deadlocks
538        occurring. We also want to underscore the idea that you can
539        combing multiple database operations together in a single atomic
540        unit of work. So for our example, we do the (slightly) wrong thing.
541    </p>
542        <pre class="programlisting">
543
544                    // Write 10 PayloadDataEntity objects to the 
545                    // store for each transaction
546                    for (int j = 0; j &lt; 10; j++) {
547                        // Instantiate an object
548                        PayloadDataEntity pd = new PayloadDataEntity();
549
550                        // Set the Object ID. This is used as the 
551                        // primary key.
552                        pd.setID(i + j);
553
554                        // The thread name is used as a secondary key, and
555                        // it is retrieved by this class's getName() 
556                        // method.
557                        pd.setThreadName(getName());
558
559                        // The last bit of data that we use is a double
560                        // that we generate randomly. This data is not
561                        // indexed.
562                        pd.setDoubleData(generator.nextDouble());
563
564                        // Do the put
565                        pdIndex.put(txn, pd);
566                    } </pre>
567        <p>
568        Having completed the inner database write loop, we could simply
569        commit the transaction and continue on to the next block of 10
570        writes. However, we want to first illustrate a few points about
571        transactional processing so instead we call our
572        <code class="function">countObjects()</code> method before calling the transaction
573        commit. <code class="function">countObjects()</code> uses a cursor to read every
574        object in the entity store and return a count of the number of objects
575        that it found. 
576    </p>
577        <p>
578        Because 
579        <code class="function">countObjects()</code> 
580        reads every object in the store, if used incorrectly the thread
581        will self-deadlock.  The writer thread has just written 500 objects
582        to the database, but because the transaction used for that write
583        has not yet been committed, each of those 500 objects are still
584        locked by the thread's transaction. If we then simply run a
585        non-transactional cursor over the store from within the same
586        thread that has locked those 500 objects, the cursor will
587        block when it tries to read one of those transactional
588        protected records. The thread immediately stops operation at that
589        point while the cursor waits for the read lock it has
590        requested.  Because that read lock will never be released (the thread
591        can never make any forward progress), this represents a
592        self-deadlock for the thread.
593    </p>
594        <p>
595        There are three ways to prevent this self-deadlock:
596    </p>
597        <div class="orderedlist">
598          <ol type="1">
599            <li>
600              <p>
601                We can move the call to
602                <code class="function">countObjects()</code> to a point after the
603                thread's transaction has committed. 
604            </p>
605            </li>
606            <li>
607              <p>
608                We can allow <code class="function">countObjects()</code> to
609                operate under the same transaction as all of the writes
610                were performed.
611            </p>
612            </li>
613            <li>
614              <p>
615                We can reduce our isolation guarantee for the application
616                by allowing uncommitted reads.
617            </p>
618            </li>
619          </ol>
620        </div>
621        <p>
622        For this example, we choose to use option 3 (uncommitted reads) to avoid
623        the deadlock. This means that we have to open our underlying database such
624        that it supports uncommitted reads, and we have to open our cursor handle
625        so that it knows to perform uncommitted reads.
626    </p>
627        <pre class="programlisting">                    // commit
628                    System.out.println(getName() + " : committing txn : " + i);
629                    System.out.println(getName() + " : Found " +
630                        countObjects(txn) + " objects in the store."); </pre>
631        <p>
632    Having performed this somewhat inelegant counting of the objects in the
633    database, we can now commit the transaction.
634</p>
635        <pre class="programlisting">                    try {
636                        txn.commit();
637                        txn = null;
638                    } catch (DatabaseException e) {
639                        System.err.println("Error on txn commit: " +
640                            e.toString());
641                    }
642                    retry = false; </pre>
643        <p>
644    If all goes well with the commit, we are done and we can move on to the
645    next batch of 10 objects to add to the store. However, in the event
646    of an error, we must handle our exceptions correctly. The first of
647    these is a deadlock exception. In the event of a deadlock, we want to
648    abort and retry the transaction, provided that we have not already
649    exceeded our retry limit for this transaction.
650</p>
651        <pre class="programlisting">                } catch (DeadlockException de) {
652                    System.out.println("################# " + getName() +
653                        " : caught deadlock");
654                    // retry if necessary
655                    if (retry_count &lt; MAX_RETRY) {
656                        System.err.println(getName() +
657                            " : Retrying operation.");
658                        retry = true;
659                        retry_count++;
660                    } else {
661                        System.err.println(getName() +
662                            " : out of retries. Giving up.");
663                        retry = false;
664                    } </pre>
665        <p>
666    In the event of a standard, non-specific database exception, we simply
667    log the exception and then give up (the transaction is not retried).
668</p>
669        <pre class="programlisting">                } catch (DatabaseException e) {
670                    // abort and don't retry
671                    retry = false;
672                    System.err.println(getName() +
673                        " : caught exception: " + e.toString());
674                    System.err.println(getName() +
675                        " : errno: " + e.getErrno());
676                    e.printStackTrace();  </pre>
677        <p>
678    And, finally, we always abort the transaction if the transaction handle
679    is not null. Note that immediately after committing our transaction, we
680    set the transaction handle to null to guard against aborting a
681    transaction that has already been committed.
682</p>
683        <pre class="programlisting">                } finally {
684                    if (txn != null) {
685                        try {
686                            txn.abort();
687                        } catch (Exception e) {
688                            System.err.println("Error aborting txn: " +
689                                e.toString());
690                            e.printStackTrace();
691                        }
692                    }
693                }
694            }
695        }
696    } </pre>
697        <p>
698    The final piece of our <code class="classname">StoreWriter</code> class is the
699    <code class="methodname">countObjects()</code> implementation. Notice how in
700    this example we open the cursor such that it performs uncommitted
701    reads:
702</p>
703        <pre class="programlisting">    // A method that counts every object in the store.
704
705    private int countObjects(Transaction txn)  throws DatabaseException {
706        int count = 0;
707
708        CursorConfig cc = new CursorConfig();
709        // This is ignored if the store is not opened with uncommitted read
710        // support.
711        cc.setReadUncommitted(true);
712        EntityCursor&lt;PayloadDataEntity&gt; cursor = pdIndex.entities(txn, cc);
713
714        try {
715            for (PayloadDataEntity pdi : cursor) {
716                    count++;
717            }
718        } finally {
719            if (cursor != null) {
720                cursor.close();
721            }
722        }
723
724        return count;
725
726    }
727} </pre>
728      </div>
729      <p>
730    This completes our transactional example. If you would like to
731    experiment with this code, you can find the example in the following
732    location in your DB distribution:
733</p>
734      <pre class="programlisting"><span class="emphasis"><em>DB_INSTALL</em></span>/examples_java/src/persist/txn</pre>
735    </div>
736    <div class="navfooter">
737      <hr />
738      <table width="100%" summary="Navigation footer">
739        <tr>
740          <td width="40%" align="left"><a accesskey="p" href="txnexample_java.html">Prev</a> </td>
741          <td width="20%" align="center">
742            <a accesskey="u" href="wrapup.html">Up</a>
743          </td>
744          <td width="40%" align="right"> <a accesskey="n" href="inmem_txnexample_java.html">Next</a></td>
745        </tr>
746        <tr>
747          <td width="40%" align="left" valign="top">Base API Transaction Example </td>
748          <td width="20%" align="center">
749            <a accesskey="h" href="index.html">Home</a>
750          </td>
751          <td width="40%" align="right" valign="top"> Base API In-Memory Transaction Example</td>
752        </tr>
753      </table>
754    </div>
755  </body>
756</html>
757