π English Documentation | π δΈζζζ‘£
Introduction
Rbatis is a high-performance ORM framework for Rust based on compile-time code generation. It perfectly balances development efficiency, performance, and stability, functioning as both an ORM and a dynamic SQL compiler.
AI-support
Core Advantages
1. High Performance
- π Dynamic SQL to Native Rust Translation: The key advantage - compiles dynamic SQL directly to native Rust code, achieving performance equivalent to hand-written SQL
- Zero Runtime Overhead: All SQL parsing and optimization happens at compile-time, eliminating runtime interpretation costs
- Based on Tokio Async Model: Fully utilizes Rust's async features to enhance concurrency performance
- Efficient Connection Pools: Built-in multiple connection pool implementations, optimizing database connection management
2. Reliability
- Rust Safety Features: Leverages Rust's ownership and borrowing checks to ensure memory and thread safety
- Unified Parameter Placeholders: Uses
?as a unified placeholder, supporting all drivers - Two Replacement Modes: Precompiled
#{arg}and direct replacement${arg}, meeting different scenario requirements
3. Development Efficiency
- Powerful ORM Capabilities: Automatic mapping between database tables and Rust structures
- Multiple SQL Building Methods:
- py_sql: Python-style dynamic SQL with
if,for,choose/when/otherwise,bind,trimstructures and collection operations (.sql(),.csv()) - html_sql: MyBatis-like XML templates with familiar tag structure (
<if>,<where>,<set>,<foreach>), declarative SQL building, and automatic handling of SQL fragments without requiring CDATA - Raw SQL: Direct SQL statements
- py_sql: Python-style dynamic SQL with
- CRUD Macros: Generate common CRUD operations with a single line of code
- Interceptor Plugin: Custom extension functionality
- Table Sync Plugin: Automatically create/update table structures
4. Extensibility
- Multiple Database Support: MySQL, PostgreSQL, SQLite, MSSQL, MariaDB, TiDB, CockroachDB, Oracle, TDengine, etc.
- Custom Driver Interface: Implement a simple interface to add support for new databases
- Multiple Connection Pools: FastPool (default), Deadpool, MobcPool
- Compatible with Various Web Frameworks: Seamlessly integrates with ntex, actix-web, axum, hyper, rocket, tide, warp, salvo, and more
Supported Database Drivers
Supported Connection Pools
| Connection Pool (crates.io) | GitHub Link |
|---|---|
| FastPool (default) | rbatis/fast_pool |
| Deadpool | rbatis/rbdc-pool-deadpool |
| MobcPool | rbatis/rbdc-pool-mobc |
Supported Data Types
| Data Type | Support |
|---|---|
Option |
β |
Vec |
β |
HashMap |
β |
i32, i64, f32, f64, bool, String, and other Rust base types |
β |
rbatis::rbdc::types::{Bytes, Date, DateTime, Time, Timestamp, Decimal, Json} |
β |
rbatis::plugin::page::{Page, PageRequest} |
β |
rbs::Value |
β |
serde_json::Value and other serde types |
β |
| Driver-specific types from rbdc-mysql, rbdc-pg, rbdc-sqlite, rbdc-mssql | β |
Member crates
| crate | GitHub Link |
|---|---|
| rbdc | rbdc |
| rbs | rbs |
How Rbatis Works
Rbatis uses compile-time code generation through the rbatis-codegen crate, which means:
-
π― Direct Translation to Native Rust: Dynamic SQL is converted to optimized Rust code during compilation, achieving performance identical to hand-written SQL without any runtime interpretation overhead.
-
Compilation Process:
- Lexical Analysis: Handled by
func.rsinrbatis-codegenusing Rust'ssynandquotecrates - Syntax Parsing: Performed by
parser_htmlandparser_pysqlmodules inrbatis-codegen - Abstract Syntax Tree: Built using structures defined in the
syntax_treepackage inrbatis-codegen - Intermediate Code Generation: Executed by
func.rs, which contains all the code generation functions
- Lexical Analysis: Handled by
-
Build Process Integration: The entire process runs during the
cargo buildphase as part of Rust's procedural macro compilation. The generated code is returned to the Rust compiler for LLVM compilation to produce machine code. -
Compile-Time SQL Optimization: Unlike traditional ORMs that interpret dynamic SQL at runtime (causing performance penalties), Rbatis translates SQL to native Rust code at compile-time, delivering hand-written SQL performance while maintaining ORM convenience.
Performance Benchmarks
---- bench_raw stdout ----(windows/SingleThread)
Time: 52.4187ms ,each:524 ns/op
QPS: 1906435 QPS/s
---- bench_select stdout ----(macos-M1Cpu/SingleThread)
Time: 112.927916ms ,each:1129 ns/op
QPS: 885486 QPS/s
---- bench_insert stdout ----(macos-M1Cpu/SingleThread)
Time: 346.576666ms ,each:3465 ns/op
QPS: 288531 QPS/s
Quick Start
Dependencies
# Cargo.toml [dependencies] #drivers rbdc-sqlite = { version = "4" } # rbdc-mysql = { version = "4" } # rbdc-pg = { version = "4" } # rbdc-mssql = { version = "4" } rbs = { version = "4"} rbatis = { version = "4.8"} # Other dependencies serde = { version = "1", features = ["derive"] } tokio = { version = "1", features = ["full"] } log = "0.4" fast_log = "1.6"
Basic Usage
use rbatis::rbdc::datetime::DateTime; use rbs::value; use rbatis::RBatis; use rbdc_sqlite::driver::SqliteDriver; use serde::{Deserialize, Serialize}; use serde_json::json; #[derive(Clone, Debug, Serialize, Deserialize)] pub struct Activity { pub id: Option<String>, pub name: Option<String>, pub create_time: Option<DateTime> } // Automatically generate CRUD methods crud!(Activity{}); #[tokio::main] async fn main() { // Configure logging fast_log::init(fast_log::Config::new().console()).expect("log init fail"); // Initialize rbatis let rb = RBatis::new(); // Connect to database rb.init(SqliteDriver {}, "sqlite://target/sqlite.db").expect("rb init fail"); // /// other databases // rb.init(PgDriver{}, "postgres://postgres:123456@localhost:5432/postgres").expect("pool init fail"); // rb.init(MysqlDriver{}, "mysql://root:123456@localhost:3306/test").expect("pool init fail"); // Create data let activity = Activity { id: Some("1".into()), name: Some("Test Activity".into()), create_time: Some(DateTime::now()), }; let arrays = vec![ Activity { id: Some("2".into()), name: Some("Activity 2".into()), create_time: Some(DateTime::now()) }, Activity { id: Some("3".into()), name: Some("Activity 3".into()), create_time: Some(DateTime::now()) }, ]; // Insert data let data = Activity::insert(&rb, &activity).await; // Batch insert let data = Activity::insert_batch(&rb, &arrays, 10).await; // Update by map condition (updates all fields) let data = Activity::update_by_map(&rb, &activity, value!{ "id": "1" }).await; // Update only specific columns using the "column" key in condition (GitHub issue #591) let data = Activity::update_by_map(&rb, &activity, value!{ "id": "1", "column": ["name", "status"] }).await; // Query by map condition let data = Activity::select_by_map(&rb, value!{"id":"2","name":"Activity 2"}).await; // LIKE query let data = Activity::select_by_map(&rb, value!{"name like ":"%Activity%"}).await; // Greater than query let data = Activity::select_by_map(&rb, value!{"id > ":"2"}).await; // IN query let data = Activity::select_by_map(&rb, value!{"id": &["1", "2", "3"]}).await; // Delete by map condition let data = Activity::delete_by_map(&rb, value!{"id": &["1", "2", "3"]}).await; }
Advanced Usage (html_sql)
Use #[rbatis::html_sql("html/file_path")] macro for complex queries like pagination, join queries, etc.:
#[derive(Clone, Debug, serde::Serialize, serde::Deserialize)] pub struct Activity { pub id: Option<String>, pub name: Option<String> } #[rbatis::html_sql("example/example.html")] impl Activity { // Paginated query (PageIntercept handles limit/offset automatically) pub async fn select_by_page(rb: &dyn rbatis::Executor, page_req: &rbatis::PageRequest, name: &str) -> rbatis::Result<rbatis::Page<Activity>> {impled!()} pub async fn select_by_condition(rb: &dyn rbatis::Executor,name: &str) -> rbatis::Result<Vec<Activity>> {impled!()} pub async fn update_by_id(rb: &dyn rbatis::Executor,arg: &Activity) -> rbatis::Result<rbatis::rbdc::ExecResult> {impled!()} pub async fn delete_by_id(rb: &dyn rbatis::Executor,id: &str) -> rbatis::Result<rbatis::rbdc::ExecResult> {impled!()} }
Corresponding HTML template file example/example.html:
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "https://raw.githubusercontent.com/rbatis/rbatis/master/rbatis-codegen/mybatis-3-mapper.dtd"> <mapper> <select id="select_by_page"> SELECT * FROM activity <where> <if test="name != ''"> AND name LIKE #{name} </if> </where> </select> <select id="select_by_condition"> SELECT * FROM activity <where> <if test="name != ''"> AND name LIKE #{name} </if> </where> </select> <update id="update_by_id"> ` update activity ` <set collection="arg"></set> ` where id = #{id} ` </update> <delete id="delete_by_id"> DELETE FROM activity WHERE id = #{id} </delete> </mapper>
Applicable scenarios: paginated queries, join queries, complex dynamic SQL, multi-condition search
Creating a Custom Database Driver
To implement a custom database driver for Rbatis:
- Define your driver project with dependencies:
[features] default = ["tls-rustls"] tls-rustls=["rbdc/tls-rustls"] tls-native-tls=["rbdc/tls-native-tls"] [dependencies] rbs = { version = "4"} rbdc = { version = "4", default-features = false, optional = true } fastdate = { version = "0.3" } tokio = { version = "1", features = ["full"] }
- Implement the required traits:
use rbdc::db::{Driver, MetaData, Row, Connection, ConnectOptions, Placeholder}; pub struct YourDriver{} impl Driver for YourDriver{} pub struct YourMetaData{} impl MetaData for YourMetaData{} pub struct YourRow{} impl Row for YourRow{} pub struct YourConnection{} impl Connection for YourConnection{} pub struct YourConnectOptions{} impl ConnectOptions for YourConnectOptions{} pub struct YourPlaceholder{} impl Placeholder for YourPlaceholder{} // Then use your driver: #[tokio::main] async fn main() -> Result<(), rbatis::Error> { let rb = rbatis::RBatis::new(); rb.init(YourDatabaseDriver {}, "database://username:password@host:port/dbname")?; }
More Information
Contact Us
Donations or Contact
WeChat (Please note 'rbatis' when adding as friend)


