use sqlx::MySqlPool;
use sqlx_transaction_manager::with_transaction;
#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
dotenvy::dotenv().ok();
let database_url = std::env::var("DATABASE_URL")
.unwrap_or_else(|_| "mysql://localhost/test".to_string());
let pool = MySqlPool::connect(&database_url).await?;
println!("=== Basic Transaction Example ===\n");
println!("1. Creating a user...");
with_transaction(&pool, |tx| {
Box::pin(async move {
sqlx::query("INSERT INTO users (name, email) VALUES (?, ?)")
.bind("Alice")
.bind("alice@example.com")
.execute(tx.as_executor())
.await
.map_err(|e| e.into())?;
Ok(())
})
})
.await?;
println!(" ✓ User created successfully\n");
println!("2. Creating user with profile...");
let user_id = with_transaction(&pool, |tx| {
Box::pin(async move {
let result = sqlx::query("INSERT INTO users (name, email) VALUES (?, ?)")
.bind("Bob")
.bind("bob@example.com")
.execute(tx.as_executor())
.await
.map_err(|e| e.into())?;
let user_id = result.last_insert_id() as i64;
sqlx::query("INSERT INTO profiles (user_id, bio) VALUES (?, ?)")
.bind(user_id)
.bind("Software Developer")
.execute(tx.as_executor())
.await
.map_err(|e| e.into())?;
Ok(user_id)
})
})
.await?;
println!(" ✓ User and profile created with ID: {}\n", user_id);
println!("3. Testing automatic rollback on error...");
let result: Result<(), _> = with_transaction(&pool, |tx| {
Box::pin(async move {
sqlx::query("INSERT INTO users (name, email) VALUES (?, ?)")
.bind("Charlie")
.bind("charlie@example.com")
.execute(tx.as_executor())
.await
.map_err(|e| e.into())?;
sqlx::query("SELECT * FROM non_existent_table")
.execute(tx.as_executor())
.await
.map_err(|e| e.into())?;
Ok(())
})
})
.await;
match result {
Ok(_) => println!(" ✗ Should have failed!"),
Err(e) => println!(" ✓ Transaction rolled back: {}\n", e),
}
println!("4. Returning values from transaction...");
let (user_count, profile_count): (i64, i64) = with_transaction(&pool, |tx| {
Box::pin(async move {
let users: (i64,) = sqlx::query_as("SELECT COUNT(*) FROM users")
.fetch_one(tx.as_executor())
.await
.map_err(|e| e.into())?;
let profiles: (i64,) = sqlx::query_as("SELECT COUNT(*) FROM profiles")
.fetch_one(tx.as_executor())
.await
.map_err(|e| e.into())?;
Ok((users.0, profiles.0))
})
})
.await?;
println!(" Users: {}, Profiles: {}\n", user_count, profile_count);
println!("=== All examples completed successfully ===");
pool.close().await;
Ok(())
}