Exception handling was illustrated previously in Implementing the Main Program and Using Transactions exception handling in a Sleepycat Java Collections API application in more detail.
There are two exceptions that must be treated specially: RunRecoveryException and DeadlockException.
RunRecoveryException is thrown when the only solution is to shut down the application and run recovery. All applications must catch this exception and follow the recovery procedure.
When DeadlockException is thrown, the application should normally retry the operation. If a deadlock continues to occur for some maximum number of retries, the application should give up and try again later or take other corrective actions. The Sleepycat Java Collections API provides two APIs for transaction execution.
When using the CurrentTransaction class directly, the application must catch DeadlockException and follow the procedure described previously.
When using the TransactionRunner class, retries are performed automatically and the application need only handle the case where the maximum number of retries has been reached. In that case, TransactionRunner.run will throw DeadlockException.
When using the TransactionRunner class there are two other considerations.
First, if the application-defined TransactionWorker.doWork method throws an exception the transaction will automatically be aborted, and otherwise the transaction will automatically be committed. Applications should design their transaction processing with this in mind.
Second, please be aware that TransactionRunner.run unwraps exceptions in order to discover whether a nested exception is a DeadlockException. This is particularly important since all Berkeley DB exceptions that occur while calling a stored collection method are wrapped with a RuntimeExceptionWrapper. This wrapping is necessary because Berkeley DB exceptions are checked exceptions, and the Java collections API does not allow such exceptions to be thrown.
When calling TransactionRunner.run, the unwrapped (nested) exception will be unwrapped and thrown automatically. If you are not using TransactionRunner or if you are handling exceptions directly for some other reason, use the ExceptionUnwrapper.unwrap method to get the nested exception. For example, this can be used to discover that an exception is a RunRecoveryException as shown below.
import com.sleepycat.util.ExceptionUnwrapper; ... catch (Exception e) { e = ExceptionUnwrapper.unwrap(e); if (e instanceof RunRecoveryException) { // follow recovery procedure } }