Coroutine Database driver Connectivity.based on mco
- High concurrency,based on coroutine
- No
Future<'q,Output=*>
,Noasync fn
, No.await
, no Poll* func,NoPin
- Optimize the trait system so that it has intelligent hints of the base method
- NativeTls and TCP connections are supported
- Low coupling,The database driver and the abstraction layer are designed separately
- Lightweight, no over-design, only have macro with intelligent tips
- Inspired by golang, mco, sqlx
crates | Concurrency | feature level | All Smart tips | Libc |
have proc macro | separation driver | support env/crates |
---|---|---|---|---|---|---|---|
cdbc | CSP(mco) | lower | √ | only sqlite | Don't need | √ | mco , mco/std/http , native-thread ,tokio-spawn_blocking |
rbatis | Future(tokio) | heavy-weight | √ | only sqlite | only py_sql,html_sql | x | tokio, async_std, smol |
sqlx | Future(tokio) | lower | x | only sqlite | only derive(StructOpt) | x | tokio, async_std, smol |
diesel | Native Thread | lower | x | all-libc | derive(Queryable) | x | native thread |
crates | Requests/sec | Mem | CpuLoad |
---|---|---|---|
cdbc-mco-http | 4606 | 30MB | 6% |
sqlx-axum-tokio | 4560 | 17MB | 8% |
sqlx-actix-async-std | 559.00 | 22MB | 2% |
diesel | * | * | * |
- benchmark with wrk(docker run -it --net=host --rm williamyeh/wrk -t12 -c400 -d30s http://192.168.28.235:8000)
- see detail benchmark
cdbc
The driver abstraction lib.cdbc-mysql
CDBC mysql driver librarycdbc-pg
CDBC postgres driver librarycdbc-sqlite
CDBC sqlite driver librarycdbc-mssql
CDBC microsoft mssql driver library
- execute: Execute the query and return the total number of rows affected.
- execute_many: Execute multiple queries and return the rows affected from each query, in a stream.
- fetch: Execute the query and return the generated results as a stream.
- fetch_many: Execute multiple queries and return the generated results as a stream,from each query, in a stream.
- fetch_all: Execute the query and return all the generated results, collected into a [
Vec
]. - fetch_one: Execute the query and returns exactly one row.
- fetch_optional: Execute the query and returns at most one row.
- prepare: Prepare the SQL query to inspect the type information of its parameters and results
- prepare_with: Prepare the SQL query, with parameter type information, to inspect the type information about its parameters and results.
- Pool: begin(),commit(),rollback()
- Connection: begin(),commit(),rollback()
use example:
cargo.toml
#must dep
cdbc = {version = "0.1"}
#optional dep
cdbc-mysql = {version = "0.1"}
cdbc-pg = {version = "0.1"}
cdbc-sqlite = {version = "0.1"}
- CRUD
#[cdbc::crud]
#[derive(Debug, Clone)]
pub struct BizActivity {
pub id: Option<String>,
pub name: Option<String>,
pub age: Option<i32>,
pub delete_flag: Option<i32>,
}
fn main() -> cdbc::Result<()> {
let pool = make_sqlite()?;
let arg = BizActivity {
id: Some("2".to_string()),
name: Some("2".to_string()),
age: Some(2),
delete_flag: Some(1),
};
CRUD::insert(&mut pool,arg.clone());
let v:BizActivity = CRUD::find(&mut tx,"id = 1")?;
CRUD::update( &mut pool.clone(), arg.clone(),"id = 1");
CRUD::delete(&mut pool.clone(),"id = 1");
}
fn make_sqlite() -> cdbc::Result<SqlitePool> {
//first. create sqlite dir/file
std::fs::create_dir_all("target/db/");
File::create("target/db/sqlite.db");
//next create table and query result
let pool = SqlitePool::connect("sqlite://target/db/sqlite.db")?;
let mut conn = pool.acquire()?;
conn.execute("CREATE TABLE biz_activity( id string, name string,age int, delete_flag int) ");
conn.execute("INSERT INTO biz_activity (id,name,age,delete_flag) values (\"1\",\"1\",1,0)");
Ok(pool)
}
- impl scan macro
use cdbc::{impl_scan};
use cdbc::scan::{Scan,Scans};
pub struct BizActivity {
pub id: Option<String>,
pub name: Option<String>,
pub delete_flag: Option<i32>,
}
impl_scan!(SqliteRow,BizActivity{id:None,name:None,delete_flag:None});
let v:Vec<BizActivity > = query!("select * from biz_activity limit 1").fetch_all(pool)?.scan()?;
- row_scan macro
use std::fs::File;
use cdbc::Executor;
use cdbc_sqlite::SqlitePool;
fn main() -> cdbc::Result<()> {
let pool = make_sqlite()?;
#[derive(Debug)]
pub struct BizActivity {
pub id: Option<String>,
pub name: Option<String>,
pub delete_flag: Option<i32>,
}
//execute
let data = pool.acquire()?.execute("update biz_activity set delete_flag where id = \"1\"")?;
println!("{:?}", data.rows_affected());
//fetch_all
let query = cdbc::query("select * from biz_activity where id = ?")
.bind("1");
let row = pool.acquire()?.fetch_all(query)?;
let data = cdbc::row_scans!(row,BizActivity{id:None,name:None,delete_flag:None})?;
println!("{:?}", data);
//fetch_one
let data = cdbc::row_scan!(
cdbc::query("select * from biz_activity where id = ?")
.bind("1")
.fetch_one(pool)?,
BizActivity{id:None,name:None,delete_flag:None})?;
println!("{:?}", data);
//transaction
let mut tx = pool.acquire()?.begin()?;
let data=tx.execute("update biz_activity set delete_flag where id = \"1\"")?;
println!("{:?}", data.rows_affected());
tx.commit()?;
Ok(())
}
fn make_sqlite() -> cdbc::Result<SqlitePool> {
//first. create sqlite dir/file
std::fs::create_dir_all("target/db/");
File::create("target/db/sqlite.db");
//next create table and query result
let pool = SqlitePool::connect("sqlite://target/db/sqlite.db")?;
let mut conn = pool.acquire()?;
conn.execute("CREATE TABLE biz_activity( id string, name string,age int, delete_flag int) ");
conn.execute("INSERT INTO biz_activity (id,name,age,delete_flag) values (\"1\",\"1\",1,0)");
Ok(pool)
}
- Processing read streams
main.rs
use std::collections::BTreeMap;
use cdbc::{Column, Decode, Executor, Row};
use cdbc::io::chan_stream::{ChanStream, TryStream};
use cdbc_sqlite::{Sqlite, SqliteRow};
use crate::make_sqlite;
#[test]
fn test_stream_sqlite() -> cdbc::Result<()> {
//first. create sqlite dir/file
let pool = make_sqlite().unwrap();
//next create table and query result
let mut conn = pool.acquire()?;
let mut data: ChanStream<SqliteRow> = conn.fetch("select * from biz_activity;");
data.try_for_each(|item| {
let mut m = BTreeMap::new();
for column in item.columns() {
let v = item.try_get_raw(column.name())?;
let r: Option<String> = Decode::<'_, Sqlite>::decode(v)?;
m.insert(column.name().to_string(), r);
}
println!("{:?}", m);
drop(m);
Ok(())
})?;
Ok(())
}