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