Documentation Index
Fetch the complete documentation index at: https://mintlify.com/sohzm/jasonisnthappy/llms.txt
Use this file to discover all available pages before exploring further.
The Transaction struct provides ACID transaction support with snapshot isolation and optimistic concurrency control.
Creating transactions
Transactions are created using Database::begin() or Database::run_transaction().
let mut tx = db.begin()?;
// Perform operations...
tx.commit()?;
For automatic retry on conflicts:
db.run_transaction(|tx| {
// Perform operations...
Ok(())
})?;
Collection operations
collection
Get a collection handle within the transaction.
pub fn collection(&mut self, name: &str) -> Result<TxCollection<'_>>
Returns: Result<TxCollection> - A transactional collection handle
Example:
let mut tx = db.begin()?;
let mut users = tx.collection("users")?;
users.insert(json!({"name": "Alice"}))?;
tx.commit()?;
create_collection
Create a new collection within the transaction.
pub fn create_collection(&mut self, name: &str) -> Result<()>
Name of the collection to create
Example:
let mut tx = db.begin()?;
tx.create_collection("orders")?;
tx.commit()?;
drop_collection
Drop (delete) a collection and all its documents.
pub fn drop_collection(&mut self, name: &str) -> Result<()>
Name of the collection to drop
Example:
let mut tx = db.begin()?;
tx.drop_collection("temp_data")?;
tx.commit()?;
rename_collection
Rename a collection.
pub fn rename_collection(&mut self, old_name: &str, new_name: &str) -> Result<()>
Current name of the collection
New name for the collection
Example:
let mut tx = db.begin()?;
tx.rename_collection("users", "customers")?;
tx.commit()?;
Transaction control
commit
Commit the transaction, making all changes permanent.
pub fn commit(&mut self) -> Result<()>
Returns: Result<()> - Ok if committed successfully, or Error::TxConflict if there was a write conflict
Example:
let mut tx = db.begin()?;
// Perform operations...
match tx.commit() {
Ok(_) => println!("Transaction committed"),
Err(Error::TxConflict) => println!("Conflict detected, retry"),
Err(e) => println!("Error: {}", e),
}
rollback
Rollback the transaction, discarding all changes.
pub fn rollback(&mut self) -> Result<()>
Example:
let mut tx = db.begin()?;
// Perform operations...
if should_cancel {
tx.rollback()?;
} else {
tx.commit()?;
}
is_active
Check if the transaction is still active.
pub fn is_active(&self) -> bool
Returns: bool - true if active, false if committed or rolled back
Transaction properties
Each transaction has the following properties:
MVCC transaction ID for versioning
Snapshot ID representing the transaction’s view of the database
Current transaction state (Active, Committed, or RolledBack)
Error handling
Transactions can fail for several reasons:
Write conflicts
Occur when two transactions try to modify the same document:
let result = tx.commit();
match result {
Err(Error::TxConflict) => {
// Another transaction modified the same data
// Retry the transaction
}
Ok(_) => println!("Success"),
Err(e) => println!("Other error: {}", e),
}
Automatic retry
Use run_transaction for automatic retry with exponential backoff:
let result = db.run_transaction(|tx| {
let mut users = tx.collection("users")?;
users.insert(json!({"name": "Bob"}))?;
Ok(())
});
// Automatically retries up to max_retries times on conflicts
Best practices
Keep transactions short
Transactions hold locks and resources. Complete them quickly:
// Good: short transaction
db.run_transaction(|tx| {
let mut users = tx.collection("users")?;
users.update_by_id("user_123", json!({"status": "active"}))?;
Ok(())
})?;
// Avoid: long-running transaction
db.run_transaction(|tx| {
// Don't do expensive I/O or computation here
let data = fetch_from_external_api()?; // BAD
thread::sleep(Duration::from_secs(10)); // BAD
Ok(())
})?;
Handle conflicts gracefully
Use run_transaction for automatic retry, or implement custom retry logic:
let mut attempts = 0;
let max_attempts = 5;
loop {
let mut tx = db.begin()?;
match perform_update(&mut tx) {
Ok(_) => match tx.commit() {
Ok(_) => break,
Err(Error::TxConflict) if attempts < max_attempts => {
attempts += 1;
thread::sleep(Duration::from_millis(10 * attempts));
continue;
}
Err(e) => return Err(e),
},
Err(e) => {
tx.rollback()?;
return Err(e);
}
}
}
Always commit or rollback
Transactions that are neither committed nor rolled back will be automatically rolled back when dropped:
{
let mut tx = db.begin()?;
let mut users = tx.collection("users")?;
users.insert(json!({"name": "Alice"}))?;
// Transaction is rolled back here when `tx` goes out of scope
}
// Explicitly commit:
{
let mut tx = db.begin()?;
let mut users = tx.collection("users")?;
users.insert(json!({"name": "Alice"}))?;
tx.commit()?; // Changes are persisted
}
Snapshot isolation
jasonisnthappy provides snapshot isolation:
- Each transaction sees a consistent snapshot of the database
- Changes made by other transactions are not visible
- Write conflicts are detected at commit time
// Transaction 1
let mut tx1 = db.begin()?;
let users1 = db.collection("users");
let count1 = users1.count()?; // Sees snapshot at tx1 start time
// Transaction 2 inserts a document
let users2 = db.collection("users");
users2.insert(json!({"name": "New User"}))?;
// Transaction 1 still sees the old count
let count_still = users1.count()?; // Same as count1
tx1.commit()?;