Transactions
Transactions ensure data integrity by grouping multiple database operations into a single atomic unit. In CQL, all operations within a transaction either succeed together or are rolled back together, maintaining consistency even when errors occur.
What are Transactions?
A transaction is a sequence of database operations that are treated as a single unit of work. Transactions provide the ACID properties:
Atomicity: All operations succeed or all are rolled back
Consistency: Database remains in a valid state
Isolation: Transactions don't interfere with each other
Durability: Committed changes are permanent
Common Use Case: Transferring money between bank accounts requires both debiting one account and crediting another. If either operation fails, both must be rolled back to prevent data corruption.
Basic Transaction Usage
CQL provides transaction support through the Transactional module. Include it in your models to access the transaction class method:
class User
include CQL::ActiveRecord::Model(Int32)
include CQL::ActiveRecord::Transactional # Enables transaction support
db_context AppDB, :users
property id : Int32?
property name : String
property email : String
property balance : Float64 = 0.0
def initialize(@name : String, @email : String, @balance : Float64 = 0.0)
end
endSimple Transaction Block
Use the Model.transaction method to wrap operations in a transaction:
Handling Rollbacks
Transactions automatically roll back if an exception is raised:
Manual Rollback with DB::Rollback
Use DB::Rollback to roll back without raising an unhandled exception:
Explicit Transaction Control
You can manually control transaction state using the yielded transaction object:
Nested Transactions (Savepoints)
CQL supports nested transactions using database savepoints. This allows you to create sub-transactions within a larger transaction:
Nested Transaction Examples
Inner Success, Outer Success
Inner Rollback, Outer Success
Inner Exception, Full Rollback
Practical Example: Bank Transfer
Here's a complete example showing how to use transactions for a bank transfer operation:
Error Handling
Catching Transaction Errors
Transaction without Exception Handling
If you don't want exceptions to be raised, check operation success manually:
Best Practices
Keep Transactions Short
Validate Before Transactions
Handle Concurrent Access
Nested Transaction Guidelines
Performance Considerations
Transaction Duration: Keep transactions as short as possible to reduce lock contention
Batch Operations: Group related operations together in a single transaction
Avoid External Calls: Don't make HTTP requests or other I/O operations within transactions
Index Usage: Ensure proper indexes exist on columns used in transaction queries
Connection Pooling: CQL automatically manages database connections within transactions
Common Pitfalls
Long-running transactions: Avoid operations that take a long time within transaction blocks
Nested transaction confusion: Remember that
DB::Rollbackonly affects the current transaction levelForgetting to reload: When dealing with concurrent access, reload records within transactions
Exception handling: Don't catch and ignore exceptions within transactions unless you explicitly roll back
The CQL transaction system provides a robust foundation for maintaining data integrity in your Crystal applications. Use transactions whenever you need to ensure that multiple database operations succeed or fail together.
Last updated
Was this helpful?