Table of Contents
Transactions cause one or more database operations to be treated as a single unit of work. Either all of the operations succeed, or all of them fail. To use transactions, you specify when a transaction begins and ends, and you specify what operations are performed within the transaction. You also define when a transaction should abort (fail) in your error handling code.
JE offers full ACID coverage through its transactions. That is, JE's transactions offer:
Atomicity.
Multiple database operations (most importantly, write operations) are treated as a single unit of work. In the event that you abort a transaction while it is in progress, then all write operations performed during the transaction are discarded. In this event, your database is left in the state it was in before the transaction began, regardless of the number or type of write operations that you may have performed during the course of the transaction.
Note that JE transactions can span one one or more Database handles. However, transactions can not span Environment handles.
Consistency.
Your JE databases will never see a partially completed transactions, no matter what happens to your application. This is true even if your application crashes while there are in-progress transactions. If the application or system fails, then either all of the database changes appear when the application next runs, or none of them appear.
Isolation.
While a transaction is in progress, your databases will appear as if there are no other operations occurring outside of the transaction. That is, operations wrapped inside a transaction will always have a clean and consistent view of your databases. They never have to contend with partially updated records.
Further, by default database read activity will return only that data that has been committed to databases. Data that has changed as the result of an on-going transaction are hidden from readers external to the transaction. Note that you can override this behavior by configuring your cursors to perform dirty reads.
Durability.
Once committed, to your databases your modifications will persist even in the event of an application or system failure.
In general you should use transactions whenever you are performing write operations. However, transaction usage does result in a performance penalty. Applications that are IO-bound might want to avoid them, especially if your databases are easily recreated such as what might occur if you are using JE as a non-persistent caching mechanism.
Before you can transactionally protect your database modifications, you must:
Enable transactions for your Environment. You do this using the EnvironmentConfig.setTransactional() method, or through the je.env.isTransactional je.properties parameter.
Enable transactions for your Database. You do this using the DatabaseConfig.setTransactional() method.
Open your Database from within a transaction. For best results, you should commit the transaction used to open your database as soon as the open operation completes. Using autocommit is an excellent way of ensuring that this happens (see below).
Once you have enabled transactions for a given environment and database, then all database modifications performed for that Database handle must be transactionally protected. Similarly, if you open an environment or database without enabling transactions, then you can not use transactions to protect modifications performed for that Environment or Databasehandle. Finally, read operations never require transactional protection regardless of whether transactions are enabled for the environment. However, remember that you do suffer at least a small performance penalty when using transactions. If possible, you should avoid transactionally protecting read-only operations.
You start a transaction using the Environment.beginTransaction() method. You can commit a transaction using the Transaction.commit() method.
For example:
import com.sleepycat.je.Database; import com.sleepycat.je.DatabaseException; import com.sleepycat.je.Environment; import com.sleepycat.je.EnvironmentConfig; import com.sleepycat.je.Transaction; ... try { EnvironmentConfig myEnvConfig = new EnvironmentConfig(); DatabaseConfig myDbConfig = new DatabaseConfig(); myEnvConfig.setTransactional(true); myDbConfig.setTransactional(true); Environment myEnv = new Environment(new File("/my/env/home"), myEnvConfig); Transaction txn = myEnv.beginTransaction(null, null); Database myDb = myEnv.openDatabase(txn, "myDbName", myDbConfig); txn.commit(); } catch (DatabaseException de) { // Exception handling goes here }