Chapter 7. Transactions
Prev |  | Next

## Chapter 7. Transactions

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.

  Note that JE support multiple levels of isolation. See Transactions and Concurrency for more information.

- Durability.

  Once committed, to your databases your modifications will persist even in the event of an application or system failure. Note that durability is available only if your application performs a sync when it commits a transaction.

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.

## Enabling and Starting Transactions

Before you can transactionally protect your database modifications, you must:

1. Enable transactions for your `Environment`. You do this using the `EnvironmentConfig.setTransactional()` method, or through the `je.env.isTransactional` `je.properties` parameter.

2. Enable transactions for your `Database`. You do this using the `DatabaseConfig.setTransactional()` method.

3. 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 `Database` handle. Finally, read operations do not 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:

    package com.sleepycat.examples.je.gettingStarted;

    import com.sleepycat.je.Database;
    import com.sleepycat.je.DatabaseConfig;
    import com.sleepycat.je.DatabaseException;
    import com.sleepycat.je.Environment;
    import com.sleepycat.je.EnvironmentConfig;
    import com.sleepycat.je.Transaction;

    import java.io.File;

    ...

    Database myDb = null;
    Environment myEnv = null;
    try {
        EnvironmentConfig myEnvConfig = new EnvironmentConfig();
        DatabaseConfig myDbConfig = new DatabaseConfig();
        myEnvConfig.setTransactional(true);
        myDbConfig.setTransactional(true);

        myEnv = new Environment(new File("/my/env/home"),
                                  myEnvConfig);

        Transaction txn = myEnv.beginTransaction(null, null);
        myDb = myEnv.openDatabase(txn, "myDbName", myDbConfig);
        txn.commit();
    } catch (DatabaseException de) {
        // Exception handling goes here
    }

Prev | Up | Next
Secondary Database Example | Home | Committing and Aborting Transactions