Transactional Cursors

You can transaction-protect your cursor operations by specifying a transaction handle at the time that you create your cursor. Beyond that, you do not ever provide a transaction handle directly to a cursor method.

Note that if you transaction-protect a cursor, then you must make sure that the cursor is closed before you either commit or abort the transaction. For example:

#include "db_cxx.h"

...

int main(void)
{
    // Environment and database opens omitted
    ...

    DbTxn *txn = NULL;
    Dbc *cursorp = NULL;

    try {

        Dbt key, data;
        key.set_data(keystr);
        key.set_size((strlen(keystr) + 1) * sizeof(char));
        key.set_data(datastr);
        key.set_size((strlen(datastr) + 1) * sizeof(char));

        DbTxn *txn = NULL;
        myEnv.txn_begin(NULL, &txn, 0);
        try {
            // Get our cursor. Note that we pass the transaction handle 
            // here.
            db.cursor(txn, &cursorp, 0); 

            // Perform our operations. Note that we do not pass a 
            // transaction handle here.
            char *replacementString = "new string";
            while (cursor->get(&key, &data, DB_NEXT) == 0) {
                data.set_data(void *)replacementString);
                data.set_size((strlen(replacementString) + 1) * 
                    sizeof(char));
                cursor->put(&key, &data, DB_CURRENT);
            }

            // We're done. Commit the transaction.
            cursor->close();
            txn->commit(0);
        } catch (DbException &e) {
            std::cerr << "Error in transaction: "
                       << e.what() << std::endl;
            cursor->close();
            txn->abort();
        }

    } catch(DbException &e) {
        std::cerr << "Error opening database and environment: "
                  << file_name << ", "
                  << envHome << std::endl;
        std::cerr << e.what() << std::endl;
    }


    return (EXIT_SUCCESS);
}