txnStart method

Future<Pointer<MDB_txn>> txnStart({
  1. Pointer<MDB_txn>? parent,
  2. LMDBFlagSet? flags,
})

Starts a new LMDB transaction.

A transaction represents a coherent set of changes to the database. All database operations must be performed within a transaction.

Parameters:

  • parent - Optional parent transaction for nested transactions
  • flags - Optional flags to modify transaction behavior

Common flags:

  • MDB_RDONLY - Read-only transaction (better performance, multiple readers allowed)
  • MDB_NOSYNC - Don't sync on commit (better performance but less safe)

Example usage patterns:

// 1. Basic read-write transaction
final txn = await db.txnStart();
try {
  await db.putUtf8(txn, 'key', 'value');
  await db.txnCommit(txn);
} catch (e) {
  await db.txnAbort(txn);
  rethrow;
}

// 2. Read-only transaction
final readTxn = await db.txnStart(
  flags: LMDBFlagSet()..add(MDB_RDONLY)
);
try {
  final value = await db.getUtf8(readTxn, 'key');
  await db.txnCommit(readTxn);
} catch (e) {
  await db.txnAbort(readTxn);
  rethrow;
}

// 3. Nested transaction
final parentTxn = await db.txnStart();
try {
  await db.putUtf8(parentTxn, 'key1', 'value1');

  // Start a child transaction
  final childTxn = await db.txnStart(parent: parentTxn);
  try {
    await db.putUtf8(childTxn, 'key2', 'value2');
    await db.txnCommit(childTxn);
  } catch (e) {
    await db.txnAbort(childTxn);
    rethrow;
  }

  await db.txnCommit(parentTxn);
} catch (e) {
  await db.txnAbort(parentTxn);
  rethrow;
}

Important notes:

  • Always pair txnStart with either txnCommit or txnAbort
  • Use try-catch blocks to ensure proper transaction handling
  • Read-only transactions can run concurrently
  • Only one write transaction can be active at a time
  • Child transactions can only be created from write transactions
  • Child transactions must be committed/aborted before parent transactions

Performance tips:

  • Use read-only transactions when possible
  • Keep transactions as short as possible
  • Consider using MDB_NOSYNC for better write performance
  • Use the Auto methods for simple operations

Throws StateError if database is not initialized Throws LMDBException if transaction cannot be started

Implementation

Future<Pointer<MDB_txn>> txnStart({
  Pointer<MDB_txn>? parent,
  LMDBFlagSet? flags,
}) async {
  final currentEnv = env;
  final txnPtr = calloc<Pointer<MDB_txn>>();

  try {
    final result = _lib.mdb_txn_begin(
      currentEnv,
      parent ?? nullptr,
      flags?.value ?? LMDBFlagSet.defaultFlags.value,
      txnPtr,
    );

    if (result != 0) {
      throw LMDBException('Failed to start transaction', result);
    }

    return txnPtr.value;
  } finally {
    calloc.free(txnPtr);
  }
}