Global Database Connection Pool (`DB`)
Global Database Connection Pool (DB)
Our application uses a global async singleton database connection pool pattern based on tokio::sync::OnceCell for efficient, safe, and manageable database access.
You can call DB().await from any async context in the application to get a database connection.
Core Concept
With let db = DB().await;, you can safely obtain a globally shared, high-performance database connection pool instance.
How to Use DB()
1. Get Connection Pool Instance
use crate::DB;
async fn some_function() -> Result<()> {
let db = DB().await;
// Use db for database operations
Ok(())
}2. Using with SeaORM
✅ Update ActiveModel
async fn update_user_avatar(user_id: i64, new_avatar: String) -> Result<()> {
let db = DB().await;
let mut user_active: user::ActiveModel = user::Entity::find_by_id(user_id)
.one(db).await?
.ok_or(Error::NotFound("User not found".to_string()))?
.into();
user_active.avatar = Set(Some(new_avatar));
user_active.update(db).await?;
Ok(())
}✅ Query Builder
async fn change_username(id: i64, new_name: String) -> Result<()> {
let db = DB().await;
user::Entity::update_many()
.col_expr(user::Column::Username, Expr::value(new_name))
.filter(user::Column::Id.eq(id))
.exec(db).await?;
Ok(())
}Why This Design?
1. tokio::sync::OnceCell: Safe Async Singleton
OnceCell ensures the connection pool is initialized only once, even under concurrent access, providing thread-safe lazy initialization.
2. Performance with Connection Pooling
DatabaseConnection is actually a connection pool, not a single connection. This allows the application to handle multiple concurrent database requests efficiently.
3. Simplified Transaction Handling
For transactions, start from the pool:
use sea_orm::TransactionTrait;
async fn transfer_funds(from_user: i64, to_user: i64, amount: Decimal) -> Result<()> {
let db = DB().await;
let txn = db.begin().await?;
// Use &txn for all operations
txn.commit().await?;
Ok(())
}Best Practices
Transaction Handling
DB().await returns a connection pool. For transactions, start a transaction from the pool and use the transaction handle for all operations within that transaction.
- Don't call
DB().awaitrepeatedly in a loop — call once and reuse. - This global access pattern is thread-safe under Rust's ownership and lifetime guarantees.