Skip to content

The Power of Transactions in SQLite with Xojo

SQLite is a powerful, serverless database engine widely used in various applications. Transactions in SQLite play a crucial role in ensuring data integrity and consistency. In Xojo, SQLiteDatabase.BeginTransaction, SQLiteDatabase.CommitTransaction, and SQLiteDatabase.RollbackTransaction provide easy ways to manage transactions.

What are Transactions?

A transaction is a sequence of SQL commands executed as a single unit, adhering to the ACID properties:

  • Atomicity: All or none of the changes are applied.
  • Consistency: The database remains in a valid state.
  • Isolation: Concurrent transactions do not interfere with each other.
  • Durability: Once committed, changes are permanent.

Basic Transaction Commands

SQLite supports three main commands for transactions:

  • BEGIN TRANSACTION: Starts a new transaction.
  • COMMIT: Finalizes changes and makes them permanent.
  • ROLLBACK: Reverts changes made since the last BEGIN TRANSACTION.

Sample in Xojo

Let’s consider a banking application where money is transferred between accounts. Without transactions, inconsistencies might occur. For example, if the first update (deducting money from one account) succeeds but the second update (adding money to another account) fails, the database will be left in an inconsistent state, reflecting a transfer that didn’t fully happen. Using transactions ensures that both updates either succeed or fail together, maintaining consistency.

Var db As New SQLiteDatabase
db.DatabaseFile = FolderItem.ShowOpenFileDialog("bank.db")
If db.Connect Then
  Try
    db.BeginTransaction
    db.ExecuteSQL("UPDATE accounts SET balance=balance-100 WHERE account_number=123")
    db.ExecuteSQL("UPDATE accounts SET balance=balance+100 WHERE account_number=456")
    db.CommitTransaction
  Catch e As DatabaseException
    db.RollbackTransaction
    MessageBox("Transaction failed: " + e.Message)
  End Try
Else
  MessageBox("Failed to connect to the database")
End If

In this example, BeginTransaction starts the transaction. The UPDATE commands perform the transfer. If successful, CommitTransaction finalizes the changes. If an error occurs, RollbackTransaction reverts all changes.

Advanced Transaction Control

SQLite also offers advanced transaction modes: DEFERRED, IMMEDIATE, and EXCLUSIVE.

  • DEFERRED: Default mode, acquires a write lock only when the first write operation occurs.
  • IMMEDIATE: Acquires a write lock immediately upon transaction start.
  • EXCLUSIVE: Prevents all other read and write operations during the transaction.

Choosing the transaction type depends on the application’s specific requirements. DEFERRED balances concurrency and consistency, while IMMEDIATE and EXCLUSIVE provide higher isolation at the cost of concurrency.

Example of Advanced Transaction

If db.Connect Then
  Try
    db.ExecuteSQL("BEGIN IMMEDIATE TRANSACTION")

    ' Perform read and write operations here

    db.CommitTransaction
  Catch e As DatabaseException
    db.RollbackTransaction
    MessageBox("Transaction failed: " + e.Message)
  End Try
Else
  MessageBox("Failed to connect to the database")
End If

In this example, an IMMEDIATE transaction ensures exclusive access from the start.

Transaction Speed Considerations

The speed of transactions in SQLite can be influenced by various factors:

  • Batching Operations: Grouping multiple operations in a single transaction can significantly improve performance.
  • Disk I/O: The underlying storage medium and its I/O performance impact transaction speed.
  • Transaction Type: IMMEDIATE and EXCLUSIVE transactions might be slower due to locking mechanisms but provide higher isolation.

Batching multiple operations into a single transaction reduces the overhead of repeatedly acquiring and releasing locks, leading to faster execution.

Benefits of Using Transactions

Using transactions offers numerous benefits:

  1. Atomicity: Prevents the database from being left in an inconsistent state due to partial updates.
  2. Consistency: Ensures the integrity of the database by transitioning only to valid states.
  3. Isolation: Prevents interference between concurrent transactions.
  4. Durability: Ensures that committed changes are permanent, even in the event of a system failure.

By understanding and applying transactions, developers can create robust applications that handle data modifications seamlessly, minimizing the risk of errors and inconsistencies.

Based on the Ducklet Blog article. Happy coding!

Martin T. is a Xojo MVP and has been very involved in testing Android support.