🎯 Recommended Samples
Balanced sample collections from various categories for you to explore
Web Database Rust Samples
Web Rust database operations examples including SQLite connection, SQL queries, and transactions
💻 SQLite Connection rust
🟢 simple
⭐⭐
Connect to SQLite database and perform basic connection management
⏱️ 20 min
🏷️ rust, web, database
Prerequisites:
Basic Rust, rusqlite crate
// Web Rust SQLite Connection Examples
// Basic SQLite database connection and management
//
// Add to Cargo.toml:
// [dependencies]
// rusqlite = "0.30"
use rusqlite::{Connection, Result as SqliteResult};
use std::path::Path;
// 1. Basic Connection
/// Create or open in-memory database
fn create_memory_db() -> SqliteResult<Connection> {
Connection::open_in_memory()
}
/// Create or open file-based database
fn create_file_db(db_path: &str) -> SqliteResult<Connection> {
Connection::open(db_path)
}
/// Create database if it doesn't exist
fn open_or_create_db(db_path: &str) -> SqliteResult<Connection> {
if !Path::new(db_path).exists() {
println!("Creating new database: {}", db_path);
}
Connection::open(db_path)
}
// 2. Connection Information
/// Get database path
fn get_db_path(conn: &Connection) -> SqliteResult<String> {
let path = conn.path()
.and_then(|p| p.to_str())
.unwrap_or(":memory:")
.to_string();
Ok(path)
}
/// Check if database is in-memory
fn is_in_memory(conn: &Connection) -> bool {
conn.path().is_none()
}
/// Get database version
fn get_db_version(conn: &Connection) -> SqliteResult<String> {
conn.query_row("SELECT sqlite_version()", [], |row| {
row.get(0)
})
}
// 3. Database Settings
/// Enable foreign keys
fn enable_foreign_keys(conn: &Connection) -> SqliteResult<()> {
conn.execute("PRAGMA foreign_keys = ON", [])?;
Ok(())
}
/// Set journal mode
fn set_journal_mode(conn: &Connection, mode: &str) -> SqliteResult<()> {
conn.execute(&format!("PRAGMA journal_mode = {}", mode), [])?;
Ok(())
}
/// Set synchronous mode
fn set_synchronous(conn: &Connection, mode: &str) -> SqliteResult<()> {
conn.execute(&format!("PRAGMA synchronous = {}", mode), [])?;
Ok(())
}
/// Set busy timeout (milliseconds)
fn set_busy_timeout(conn: &Connection, timeout_ms: u32) -> SqliteResult<()> {
conn.busy_timeout(timeout_ms)
}
/// Set cache size (negative value = KB)
fn set_cache_size(conn: &Connection, size: i32) -> SqliteResult<()> {
conn.execute(&format!("PRAGMA cache_size = {}", size), [])?;
Ok(())
}
// 4. Connection Pool (Simple)
/// Simple connection wrapper
struct DatabasePool {
connections: Vec<Connection>,
}
impl DatabasePool {
/// Create a new connection pool
fn new(db_path: &str, pool_size: usize) -> SqliteResult<Self> {
let mut connections = Vec::new();
for _ in 0..pool_size {
connections.push(Connection::open(db_path)?);
}
Ok(DatabasePool { connections })
}
/// Get a connection from the pool
fn get_connection(&mut self) -> Option<&Connection> {
self.connections.first()
}
/// Get pool size
fn size(&self) -> usize {
self.connections.len()
}
}
// 5. Database Creation
/// Create a new database with initial schema
fn create_initialized_db(db_path: &str) -> SqliteResult<Connection> {
let conn = Connection::open(db_path)?;
// Enable foreign keys
enable_foreign_keys(&conn)?;
// Create tables
conn.execute(
"CREATE TABLE IF NOT EXISTS users (
id INTEGER PRIMARY KEY AUTOINCREMENT,
name TEXT NOT NULL,
email TEXT UNIQUE NOT NULL,
created_at TEXT DEFAULT CURRENT_TIMESTAMP
)",
[],
)?;
conn.execute(
"CREATE TABLE IF NOT EXISTS posts (
id INTEGER PRIMARY KEY AUTOINCREMENT,
user_id INTEGER NOT NULL,
title TEXT NOT NULL,
content TEXT,
created_at TEXT DEFAULT CURRENT_TIMESTAMP,
FOREIGN KEY (user_id) REFERENCES users(id)
)",
[],
)?;
Ok(conn)
}
// 6. Backup Database
/// Create a backup of the database
fn backup_database(source_path: &str, backup_path: &str) -> SqliteResult<()> {
let source = Connection::open(source_path)?;
let backup = Connection::open(backup_path)?;
let src_path = source.backup(rusqlite::DatabaseName::Main, &backup, rusqlite::DatabaseName::Main, None)?;
src_path.run_to_completion()
}
// 7. Database Statistics
/// Get database size in bytes
fn get_db_size(conn: &Connection) -> SqliteResult<u64> {
conn.query_row("SELECT page_count * page_size as size FROM pragma_page_count(), pragma_page_size()", [], |row| {
row.get(0)
})
}
/// Get table count
fn get_table_count(conn: &Connection) -> SqliteResult<usize> {
conn.query_row("SELECT count(*) FROM sqlite_master WHERE type='table'", [], |row| {
row.get(0)
})
}
/// Get database page count
fn get_page_count(conn: &Connection) -> SqliteResult<usize> {
conn.query_row("PRAGMA page_count", [], |row| {
row.get(0)
})
}
// 8. Integrity Check
/// Perform integrity check
fn check_integrity(conn: &Connection) -> SqliteResult<bool> {
let result: String = conn.query_row("PRAGMA integrity_check", [], |row| {
row.get(0)
})?;
Ok(result == "ok")
}
/// Perform quick check
fn quick_check(conn: &Connection) -> SqliteResult<bool> {
let result: String = conn.query_row("PRAGMA quick_check", [], |row| {
row.get(0)
})?;
Ok(result == "ok")
}
// 9. Optimize Database
/// Vacuum database to reclaim space
fn vacuum_database(conn: &Connection) -> SqliteResult<()> {
conn.execute("VACUUM", [])
}
/// Analyze database for query optimization
fn analyze_database(conn: &Connection) -> SqliteResult<()> {
conn.execute("ANALYZE", [])
}
/// Reindex database
fn reindex_database(conn: &Connection) -> SqliteResult<()> {
conn.execute("REINDEX", [])
}
// 10. Close and Cleanup
/// Close database properly
fn close_database(conn: Connection) -> SqliteResult<()> {
// Ensure all changes are committed
conn.execute("PRAGMA optimize", [])?;
drop(conn);
Ok(())
}
// Usage Examples
fn main() -> SqliteResult<()> {
println!("=== Web Rust SQLite Connection Examples ===\n");
// 1. Create in-memory database
println!("--- 1. In-Memory Database ---");
let mem_conn = create_memory_db()?;
println!("Created in-memory database");
println!("Is in-memory: {}", is_in_memory(&mem_conn));
// 2. Create file-based database
println!("\n--- 2. File-Based Database ---");
let db_path = "test.db";
let file_conn = open_or_create_db(db_path)?;
println!("Database path: {}", get_db_path(&file_conn)?);
println!("SQLite version: {}", get_db_version(&file_conn)?);
// 3. Configure database
println!("\n--- 3. Database Configuration ---");
enable_foreign_keys(&file_conn)?;
set_journal_mode(&file_conn, "WAL")?;
set_busy_timeout(&file_conn, 5000)?;
println!("Database configured successfully");
// 4. Create initialized database
println!("\n--- 4. Create Database with Schema ---");
let init_db_path = "initialized.db";
let init_conn = create_initialized_db(init_db_path)?;
println!("Database created with tables");
println!("Table count: {}", get_table_count(&init_conn)?);
// 5. Database statistics
println!("\n--- 5. Database Statistics ---");
println!("Size: {} bytes", get_db_size(&init_conn)?);
println!("Page count: {}", get_page_count(&init_conn)?);
// 6. Integrity check
println!("\n--- 6. Integrity Check ---");
println!("Integrity check passed: {}", check_integrity(&init_conn)?);
println!("Quick check passed: {}", quick_check(&init_conn)?);
// 7. Optimization
println!("\n--- 7. Database Optimization ---");
analyze_database(&init_conn)?;
println!("Database analyzed for optimization");
// 8. Connection pool
println!("\n--- 8. Simple Connection Pool ---");
let mut pool = DatabasePool::new("pool.db", 3)?;
println!("Pool size: {}", pool.size());
if let Some(conn) = pool.get_connection() {
println!("Got connection from pool");
}
// 9. Backup
println!("\n--- 9. Database Backup ---");
let backup_path = "test_backup.db";
backup_database(init_db_path, backup_path)?;
println!("Database backed up to: {}", backup_path);
// 10. Cleanup
println!("\n--- 10. Cleanup ---");
close_database(init_conn)?;
println!("Database closed properly");
// Note: In production, you'd want to remove these test files
// std::fs::remove_file("test.db")?;
// std::fs::remove_file("initialized.db")?;
// std::fs::remove_file("test_backup.db")?;
// std::fs::remove_file("pool.db")?;
println!("\n=== All SQLite Connection Examples Completed ===");
Ok(())
}
💻 SQL Query Execution rust
🟡 intermediate
⭐⭐⭐
Execute SELECT, INSERT, UPDATE, and DELETE queries with proper parameter binding
⏱️ 25 min
🏷️ rust, web, database, sql
Prerequisites:
Intermediate Rust, rusqlite crate, SQL basics
// Web Rust SQL Query Examples
// Execute various SQL queries with parameter binding
//
// Add to Cargo.toml:
// [dependencies]
// rusqlite = "0.30"
use rusqlite::{Connection, Result as SqliteResult, params};
use serde::Serialize;
// 1. INSERT Operations
/// User struct representing database record
#[derive(Debug, Serialize)]
struct User {
id: i64,
name: String,
email: String,
created_at: String,
}
/// Insert a single user
fn insert_user(conn: &Connection, name: &str, email: &str) -> SqliteResult<i64> {
conn.execute(
"INSERT INTO users (name, email) VALUES (?1, ?2)",
params![name, email],
)?;
Ok(conn.last_insert_rowid())
}
/// Insert multiple users using transaction
fn insert_users_batch(conn: &Connection, users: &[(&str, &str)]) -> SqliteResult<Vec<i64>> {
let mut ids = Vec::new();
for (name, email) in users {
conn.execute(
"INSERT INTO users (name, email) VALUES (?1, ?2)",
params![name, email],
)?;
ids.push(conn.last_insert_rowid());
}
Ok(ids)
}
/// Insert user with return value
fn insert_user_and_get(conn: &Connection, name: &str, email: &str) -> SqliteResult<User> {
conn.execute(
"INSERT INTO users (name, email) VALUES (?1, ?2)",
params![name, email],
)?;
let id = conn.last_insert_rowid();
get_user_by_id(conn, id)
}
/// Insert or replace (upsert)
fn insert_or_replace_user(conn: &Connection, id: i64, name: &str, email: &str) -> SqliteResult<()> {
conn.execute(
"INSERT OR REPLACE INTO users (id, name, email) VALUES (?1, ?2, ?3)",
params![id, name, email],
)?;
Ok(())
}
// 2. SELECT Operations
/// Get user by ID
fn get_user_by_id(conn: &Connection, id: i64) -> SqliteResult<User> {
conn.query_row(
"SELECT id, name, email, created_at FROM users WHERE id = ?1",
params![id],
|row| {
Ok(User {
id: row.get(0)?,
name: row.get(1)?,
email: row.get(2)?,
created_at: row.get(3)?,
})
},
)
}
/// Get user by email
fn get_user_by_email(conn: &Connection, email: &str) -> SqliteResult<User> {
conn.query_row(
"SELECT id, name, email, created_at FROM users WHERE email = ?1",
params![email],
|row| {
Ok(User {
id: row.get(0)?,
name: row.get(1)?,
email: row.get(2)?,
created_at: row.get(3)?,
})
},
)
}
/// Get all users
fn get_all_users(conn: &Connection) -> SqliteResult<Vec<User>> {
let mut stmt = conn.prepare(
"SELECT id, name, email, created_at FROM users ORDER BY created_at DESC"
)?;
let user_iter = stmt.query_map([], |row| {
Ok(User {
id: row.get(0)?,
name: row.get(1)?,
email: row.get(2)?,
created_at: row.get(3)?,
})
})?;
user_iter.collect()
}
/// Get users with pagination
fn get_users_paginated(conn: &Connection, limit: usize, offset: usize) -> SqliteResult<Vec<User>> {
let mut stmt = conn.prepare(
"SELECT id, name, email, created_at FROM users ORDER BY id LIMIT ?1 OFFSET ?2"
)?;
let user_iter = stmt.query_map(params![limit, offset], |row| {
Ok(User {
id: row.get(0)?,
name: row.get(1)?,
email: row.get(2)?,
created_at: row.get(3)?,
})
})?;
user_iter.collect()
}
/// Search users by name
fn search_users_by_name(conn: &Connection, name_pattern: &str) -> SqliteResult<Vec<User>> {
let mut stmt = conn.prepare(
"SELECT id, name, email, created_at FROM users WHERE name LIKE ?1 ORDER BY name"
)?;
let user_iter = stmt.query_map(params![format!("%{}%", name_pattern)], |row| {
Ok(User {
id: row.get(0)?,
name: row.get(1)?,
email: row.get(2)?,
created_at: row.get(3)?,
})
})?;
user_iter.collect()
}
// 3. UPDATE Operations
/// Update user name
fn update_user_name(conn: &Connection, id: i64, new_name: &str) -> SqliteResult<usize> {
conn.execute(
"UPDATE users SET name = ?1 WHERE id = ?2",
params![new_name, id],
)
}
/// Update user email
fn update_user_email(conn: &Connection, id: i64, new_email: &str) -> SqliteResult<usize> {
conn.execute(
"UPDATE users SET email = ?1 WHERE id = ?2",
params![new_email, id],
)
}
/// Update multiple fields
fn update_user(conn: &Connection, id: i64, name: &str, email: &str) -> SqliteResult<usize> {
conn.execute(
"UPDATE users SET name = ?1, email = ?2 WHERE id = ?3",
params![name, email, id],
)
}
/// Increment user access counter
#[allow(dead_code)]
fn increment_user_counter(conn: &Connection, id: i64) -> SqliteResult<usize> {
conn.execute(
"UPDATE users SET access_count = COALESCE(access_count, 0) + 1 WHERE id = ?1",
params![id],
)
}
// 4. DELETE Operations
/// Delete user by ID
fn delete_user(conn: &Connection, id: i64) -> SqliteResult<usize> {
conn.execute("DELETE FROM users WHERE id = ?1", params![id])
}
/// Delete users by condition
fn delete_users_by_name(conn: &Connection, name: &str) -> SqliteResult<usize> {
conn.execute("DELETE FROM users WHERE name = ?1", params![name])
}
/// Delete all users (use with caution!)
fn delete_all_users(conn: &Connection) -> SqliteResult<usize> {
conn.execute("DELETE FROM users", [])
}
// 5. COUNT and Aggregates
/// Count total users
fn count_users(conn: &Connection) -> SqliteResult<usize> {
conn.query_row("SELECT COUNT(*) FROM users", [], |row| {
row.get(0)
})
}
/// Count users by name pattern
fn count_users_by_pattern(conn: &Connection, pattern: &str) -> SqliteResult<usize> {
conn.query_row(
"SELECT COUNT(*) FROM users WHERE name LIKE ?1",
params![format!("%{}%", pattern)],
|row| row.get(0)
)
}
/// Get user statistics
#[derive(Debug)]
struct UserStats {
total_users: usize,
users_today: usize,
avg_name_length: f64,
}
fn get_user_stats(conn: &Connection) -> SqliteResult<UserStats> {
conn.query_row(
"SELECT
COUNT(*) as total,
COUNT(CASE WHEN date(created_at) = date('now') THEN 1 END) as today,
AVG(LENGTH(name)) as avg_length
FROM users",
[],
|row| {
Ok(UserStats {
total_users: row.get(0)?,
users_today: row.get(1)?,
avg_name_length: row.get(2)?,
})
},
)
}
// 6. Complex Queries
/// Get users with their post counts
#[derive(Debug)]
struct UserWithPostCount {
id: i64,
name: String,
email: String,
post_count: i64,
}
fn get_users_with_post_count(conn: &Connection) -> SqliteResult<Vec<UserWithPostCount>> {
let mut stmt = conn.prepare(
"SELECT u.id, u.name, u.email, COUNT(p.id) as post_count
FROM users u
LEFT JOIN posts p ON u.id = p.user_id
GROUP BY u.id
ORDER BY post_count DESC"
)?;
let user_iter = stmt.query_map([], |row| {
Ok(UserWithPostCount {
id: row.get(0)?,
name: row.get(1)?,
email: row.get(2)?,
post_count: row.get(3)?,
})
})?;
user_iter.collect()
}
/// Get recent activity
#[derive(Debug)]
struct RecentActivity {
user_name: String,
action_type: String,
title: String,
created_at: String,
}
fn get_recent_activity(conn: &Connection, limit: usize) -> SqliteResult<Vec<RecentActivity>> {
let mut stmt = conn.prepare(
"SELECT u.name, 'post' as type, p.title, p.created_at
FROM posts p
JOIN users u ON p.user_id = u.id
ORDER BY p.created_at DESC
LIMIT ?1"
)?;
let activity_iter = stmt.query_map(params![limit], |row| {
Ok(RecentActivity {
user_name: row.get(0)?,
action_type: row.get(1)?,
title: row.get(2)?,
created_at: row.get(3)?,
})
})?;
activity_iter.collect()
}
// Usage Examples
fn main() -> SqliteResult<()> {
println!("=== Web Rust SQL Query Examples ===\n");
let conn = Connection::open_in_memory()?;
// Create tables
conn.execute(
"CREATE TABLE users (
id INTEGER PRIMARY KEY AUTOINCREMENT,
name TEXT NOT NULL,
email TEXT UNIQUE NOT NULL,
created_at TEXT DEFAULT CURRENT_TIMESTAMP
)",
[],
)?;
conn.execute(
"CREATE TABLE posts (
id INTEGER PRIMARY KEY AUTOINCREMENT,
user_id INTEGER NOT NULL,
title TEXT NOT NULL,
content TEXT,
created_at TEXT DEFAULT CURRENT_TIMESTAMP,
FOREIGN KEY (user_id) REFERENCES users(id)
)",
[],
)?;
// 1. INSERT examples
println!("--- 1. INSERT Operations ---");
let id1 = insert_user(&conn, "Alice", "[email protected]")?;
println!("Inserted user with ID: {}", id1);
let id2 = insert_user(&conn, "Bob", "[email protected]")?;
println!("Inserted user with ID: {}", id2);
let batch_ids = insert_users_batch(&conn, &[
("Charlie", "[email protected]"),
("Diana", "[email protected]"),
])?;
println!("Batch inserted users: {:?}", batch_ids);
// 2. SELECT examples
println!("\n--- 2. SELECT Operations ---");
match get_user_by_id(&conn, id1) {
Ok(user) => println!("User by ID: {:?}", user),
Err(e) => println!("Error: {}", e),
}
let all_users = get_all_users(&conn)?;
println!("All users: {} found", all_users.len());
for user in &all_users {
println!(" - {} ({})", user.name, user.email);
}
// 3. SEARCH examples
println!("\n--- 3. SEARCH Operations ---");
let search_results = search_users_by_name(&conn, "a")?;
println!("Users matching 'a': {} found", search_results.len());
// 4. UPDATE examples
println!("\n--- 4. UPDATE Operations ---");
let updated = update_user_name(&conn, id1, "Alice Smith")?;
println!("Updated {} row(s)", updated);
// 5. COUNT and stats
println!("\n--- 5. COUNT and Statistics ---");
let count = count_users(&conn)?;
println!("Total users: {}", count);
let stats = get_user_stats(&conn)?;
println!("User stats: {:?}", stats);
// 6. DELETE examples
println!("\n--- 6. DELETE Operations ---");
let deleted = delete_user(&conn, id2)?;
println!("Deleted {} user(s)", deleted);
println!("\n=== All SQL Query Examples Completed ===");
Ok(())
}
💻 Transaction Handling rust
🟡 intermediate
⭐⭐⭐⭐
Manage database transactions with commit, rollback, and error handling
⏱️ 30 min
🏷️ rust, web, database, transaction
Prerequisites:
Intermediate Rust, rusqlite crate, transaction basics
// Web Rust Transaction Handling Examples
// Transaction management with commit and rollback
//
// Add to Cargo.toml:
// [dependencies]
// rusqlite = "0.30"
use rusqlite::{Connection, Result as SqliteResult, Transaction, params};
// 1. Basic Transaction
/// Execute code within a transaction
fn execute_in_transaction<F>(conn: &Connection, mut operation: F) -> SqliteResult<()>
where
F: FnMut(&Transaction) -> SqliteResult<()>,
{
let tx = conn.unchecked_transaction()?;
operation(&tx)?;
tx.commit()?;
Ok(())
}
/// Create tables within a transaction
fn create_tables_transaction(conn: &Connection) -> SqliteResult<()> {
execute_in_transaction(conn, |tx| {
tx.execute(
"CREATE TABLE IF NOT EXISTS accounts (
id INTEGER PRIMARY KEY AUTOINCREMENT,
name TEXT NOT NULL,
balance INTEGER NOT NULL DEFAULT 0
)",
[],
)?;
tx.execute(
"CREATE TABLE IF NOT EXISTS transactions_log (
id INTEGER PRIMARY KEY AUTOINCREMENT,
from_account INTEGER,
to_account INTEGER,
amount INTEGER NOT NULL,
timestamp TEXT DEFAULT CURRENT_TIMESTAMP,
FOREIGN KEY (from_account) REFERENCES accounts(id),
FOREIGN KEY (to_account) REFERENCES accounts(id)
)",
[],
)?;
Ok(())
})
}
// 2. Transfer Money (Classic Transaction Example)
/// Transfer money between accounts with transaction
fn transfer_money(
conn: &Connection,
from_id: i64,
to_id: i64,
amount: i64,
) -> SqliteResult<()> {
let tx = conn.unchecked_transaction()?;
// Check from account has sufficient balance
let balance: i64 = tx.query_row(
"SELECT balance FROM accounts WHERE id = ?1",
params![from_id],
|row| row.get(0),
)?;
if balance < amount {
return Err(rusqlite::Error::SqliteFailure(
rusqlite::ffi::Error::new(rusqlite::ffi::SQLITE_CONSTRAINT),
Some("Insufficient funds".to_string()),
));
}
// Deduct from sender
tx.execute(
"UPDATE accounts SET balance = balance - ?1 WHERE id = ?2",
params![amount, from_id],
)?;
// Add to receiver
tx.execute(
"UPDATE accounts SET balance = balance + ?1 WHERE id = ?2",
params![amount, to_id],
)?;
// Log transaction
tx.execute(
"INSERT INTO transactions_log (from_account, to_account, amount) VALUES (?1, ?2, ?3)",
params![from_id, to_id, amount],
)?;
// Commit transaction
tx.commit()?;
Ok(())
}
/// Transfer with automatic rollback on error
fn transfer_safe(
conn: &Connection,
from_id: i64,
to_id: i64,
amount: i64,
) -> Result<String, Box<dyn std::error::Error>> {
let mut tx = conn.unchecked_transaction()?;
// Perform operations
let result: SqliteResult<()> = (|| {
// Deduct from sender
tx.execute(
"UPDATE accounts SET balance = balance - ?1 WHERE id = ?2",
params![amount, from_id],
)?;
// Add to receiver
tx.execute(
"UPDATE accounts SET balance = balance + ?1 WHERE id = ?2",
params![amount, to_id],
)?;
// Log
tx.execute(
"INSERT INTO transactions_log (from_account, to_account, amount) VALUES (?1, ?2, ?3)",
params![from_id, to_id, amount],
)?;
Ok(())
})();
match result {
Ok(_) => {
tx.commit()?;
Ok("Transfer successful".to_string())
}
Err(e) => {
tx.rollback()?;
Err(format!("Transfer failed: {}", e).into())
}
}
}
// 3. Nested Transactions (Savepoints)
/// Create nested transaction using savepoint
fn create_account_with_initial_balance(
tx: &Transaction,
name: &str,
initial_balance: i64,
) -> SqliteResult<i64> {
tx.execute(
"INSERT INTO accounts (name, balance) VALUES (?1, ?2)",
params![name, initial_balance],
)?;
Ok(tx.last_insert_rowid())
}
/// Batch transfer with savepoints
fn batch_transfer(
conn: &Connection,
transfers: Vec<(i64, i64, i64)>,
) -> SqliteResult<usize> {
let tx = conn.unchecked_transaction()?;
let mut success_count = 0;
for (from, to, amount) in transfers {
// Use savepoint for each transfer
let sp = tx.savepoint()?;
match sp.execute(
"UPDATE accounts SET balance = balance - ?1 WHERE id = ?2",
params![amount, from],
) {
Ok(_) => {
sp.execute(
"UPDATE accounts SET balance = balance + ?1 WHERE id = ?2",
params![amount, to],
)?;
sp.commit()?;
success_count += 1;
}
Err(_) => {
sp.rollback()?;
continue;
}
}
}
tx.commit()?;
Ok(success_count)
}
// 4. Transaction Isolation Levels
/// Set transaction isolation level
fn set_isolation_level(conn: &Connection, level: &str) -> SqliteResult<()> {
conn.execute(&format!("PRAGMA read_unauthorized = {}", level), [])?;
Ok(())
}
/// Read-only transaction
fn read_only_transaction<F, R>(conn: &Connection, operation: F) -> SqliteResult<R>
where
F: FnOnce(&Transaction) -> SqliteResult<R>,
{
let tx = conn.transaction()?;
let result = operation(&tx)?;
tx.commit()?;
Ok(result)
}
// 5. Batch Operations
/// Insert multiple records in a transaction
fn batch_insert_accounts(
conn: &Connection,
accounts: Vec<(&str, i64)>,
) -> SqliteResult<Vec<i64>> {
let tx = conn.unchecked_transaction()?;
let mut ids = Vec::new();
for (name, balance) in accounts {
tx.execute(
"INSERT INTO accounts (name, balance) VALUES (?1, ?2)",
params![name, balance],
)?;
ids.push(tx.last_insert_rowid());
}
tx.commit()?;
Ok(ids)
}
/// Batch update with transaction
fn batch_update_balances(
conn: &Connection,
updates: Vec<(i64, i64)>,
) -> SqliteResult<usize> {
let tx = conn.unchecked_transaction()?;
let mut total_updated = 0;
for (id, new_balance) in updates {
total_updated += tx.execute(
"UPDATE accounts SET balance = ?1 WHERE id = ?2",
params![new_balance, id],
)?;
}
tx.commit()?;
Ok(total_updated)
}
// 6. Transaction with Retry
/// Execute transaction with retry on busy
fn transaction_with_retry<F>(
conn: &Connection,
mut operation: F,
max_retries: u32,
) -> SqliteResult<()>
where
F: FnMut(&Transaction) -> SqliteResult<()>,
{
let mut retries = 0;
loop {
let tx = conn.unchecked_transaction()?;
match operation(&tx) {
Ok(_) => {
return tx.commit();
}
Err(rusqlite::Error::SqliteFailure(err, _))
if err.code == rusqlite::ffi::ErrorCode::DatabaseBusy =>
{
retries += 1;
if retries >= max_retries {
return Err(rusqlite::Error::SqliteFailure(err, None));
}
std::thread::sleep(std::time::Duration::from_millis(100));
continue;
}
Err(e) => return Err(e),
}
}
}
// 7. Deferred Transaction
/// Begin deferred transaction (starts on first statement)
fn deferred_transaction<F>(conn: &Connection, operation: F) -> SqliteResult<()>
where
F: FnOnce(&Transaction) -> SqliteResult<()>,
{
let tx = conn.transaction_with_behavior(rusqlite::TransactionBehavior::Deferred)?;
operation(&tx)?;
tx.commit()?;
Ok(())
}
// 8. Immediate Transaction
/// Begin immediate transaction (locks immediately)
fn immediate_transaction<F>(conn: &Connection, operation: F) -> SqliteResult<()>
where
F: FnOnce(&Transaction) -> SqliteResult<()>,
{
let tx = conn.transaction_with_behavior(rusqlite::TransactionBehavior::Immediate)?;
operation(&tx)?;
tx.commit()?;
Ok(())
}
// 9. Exclusive Transaction
/// Begin exclusive transaction (exclusive lock)
fn exclusive_transaction<F>(conn: &Connection, operation: F) -> SqliteResult<()>
where
F: FnOnce(&Transaction) -> SqliteResult<()>,
{
let tx = conn.transaction_with_behavior(rusqlite::TransactionBehavior::Exclusive)?;
operation(&tx)?;
tx.commit()?;
Ok(())
}
// 10. Transaction Status
/// Check if transaction is active
fn is_in_transaction(conn: &Connection) -> SqliteResult<bool> {
conn.query_row("PRAGMA transaction_status", [], |row| {
let status: String = row.get(0)?;
Ok(status != "0")
})
}
/// Get current transaction state
fn get_transaction_state(conn: &Connection) -> SqliteResult<String> {
conn.query_row("PRAGMA transaction_status", [], |row| {
row.get(0)
})
}
// Usage Examples
fn main() -> SqliteResult<()> {
println!("=== Web Rust Transaction Handling Examples ===\n");
let conn = Connection::open_in_memory()?;
// Create tables
create_tables_transaction(&conn)?;
println!("Created tables in transaction");
// 1. Basic transaction
println!("\n--- 1. Basic Transaction ---");
execute_in_transaction(&conn, |tx| {
tx.execute(
"INSERT INTO accounts (name, balance) VALUES (?1, ?2)",
params!["Alice", 1000],
)?;
tx.execute(
"INSERT INTO accounts (name, balance) VALUES (?1, ?2)",
params!["Bob", 500],
)?;
Ok(())
})?;
println!("Inserted initial accounts");
// 2. Transfer money
println!("\n--- 2. Transfer Money ---");
let from_id = 1;
let to_id = 2;
match transfer_money(&conn, from_id, to_id, 200) {
Ok(_) => println!("Transfer successful"),
Err(e) => println!("Transfer failed: {}", e),
}
// 3. Safe transfer with rollback
println!("\n--- 3. Safe Transfer ---");
match transfer_safe(&conn, from_id, to_id, 100) {
Ok(msg) => println!("{}", msg),
Err(e) => println!("Error: {}", e),
}
// 4. Batch operations
println!("\n--- 4. Batch Insert ---");
let accounts = vec![
("Charlie", 750),
("Diana", 1200),
("Eve", 300),
];
match batch_insert_accounts(&conn, accounts) {
Ok(ids) => println!("Batch inserted {} accounts", ids.len()),
Err(e) => println!("Batch insert failed: {}", e),
}
// 5. Batch transfer
println!("\n--- 5. Batch Transfer ---");
let transfers = vec![
(1, 3, 50), // Alice -> Charlie
(2, 4, 100), // Bob -> Diana
(3, 5, 25), // Charlie -> Eve
];
match batch_transfer(&conn, transfers) {
Ok(count) => println!("Completed {} transfers", count),
Err(e) => println!("Batch transfer failed: {}", e),
}
// 6. Transaction status
println!("\n--- 6. Transaction Status ---");
println!("In transaction: {}", is_in_transaction(&conn)?);
println!("Transaction state: {}", get_transaction_state(&conn)?);
// 7. Read-only transaction
println!("\n--- 7. Read-Only Transaction ---");
let balance: i64 = read_only_transaction(&conn, |tx| {
tx.query_row("SELECT SUM(balance) FROM accounts", [], |row| row.get(0))
})?;
println!("Total balance: {}", balance);
// 8. Deferred transaction
println!("\n--- 8. Deferred Transaction ---");
deferred_transaction(&conn, |tx| {
tx.execute(
"INSERT INTO accounts (name, balance) VALUES (?1, ?2)",
params!["Frank", 600],
)?;
Ok(())
})?;
println!("Inserted account with deferred transaction");
println!("\n=== All Transaction Handling Examples Completed ===");
Ok(())
}