10个版本
0.1.23 | 2022年3月6日 |
---|---|
0.1.22 |
|
0.1.21 | 2022年2月25日 |
0.1.11 | 2022年1月28日 |
0.1.7 |
|
#2087 in 数据库接口
每月 34次下载
用于 5 crates
220KB
4.5K SLoC
cdbc
Coroutine Database driver Connectivity,基于 mco
- 高并发,基于协程
- 不使用
Future<'q,Output=*>
,不使用async fn
,不使用.await
,没有 Poll* 函数,不使用Pin
- 优化了特质系统,使其具有基类方法的智能提示
- 支持原生Tls和TCP连接
- 低耦合,数据库驱动和抽象层分别设计
- 轻量级,没有过度设计,只有带有智能提示的宏
- 受golang, mco, sqlx 启发
为什么选择cdbc ?
crates | 并发 | 特性级别 | 所有智能提示 | Libc |
具有进程宏 | 分离驱动 | 支持env/crates |
---|---|---|---|---|---|---|---|
cdbc | CSP(mco) | 较低 | √ | 仅sqlite | 不需要 | √ | mco , mco/std/http , native-thread ,tokio-spawn_blocking |
rbatis | Future(tokio) | 重量级 | √ | 仅sqlite | 仅py_sql,html_sql | x | tokio, async_std, smol |
sqlx | Future(tokio) | 较低 | x | 仅sqlite | 仅derive(StructOpt) | x | tokio, async_std, smol |
diesel | 原生线程 | 较低 | x | 所有Libc | derive(Queryable) | x | 原生线程 |
并发基准性能(比较SQLX/Tokio/Async-std)
crates | 每秒请求数 | 内存 | CPU负载 |
---|---|---|---|
cdbc-mco-http | 4606 | 30MB | 6% |
sqlx-axum-tokio | 4560 | 17MB | 8% |
sqlx-actix-async-std | 559.00 | 22MB | 2% |
diesel | * | * | * |
- 使用wrk进行基准测试(docker run -it --net=host --rm williamyeh/wrk -t12 -c400 -d30s http://192.168.28.235:8000)
- 查看详情 基准测试
数据库支持
cdbc
驱动抽象库。cdbc-mysql
CDBC mysql 驱动库cdbc-pg
CDBC postgres 驱动库cdbc-sqlite
CDBC sqlite 驱动库cdbc-mssql
CDBC 微软 mssql 驱动库
支持的功能
- execute:执行查询并返回受影响的行数。
- execute_many:执行多个查询,并以流的形式返回每个查询受影响的行数。
- fetch:执行查询并将生成的结果作为流返回。
- fetch_many:执行多个查询,并以流的形式返回每个查询生成的结果,每个查询的结果作为一个流。
- fetch_all:执行查询并返回所有生成的结果,收集到一个 [
Vec
] 中。 - fetch_one:执行查询并返回正好一行。
- fetch_optional:执行查询并返回最多一行。
- prepare:准备SQL查询以检查其参数和结果的数据类型信息。
- prepare_with:准备带参数类型信息的SQL查询,以检查其参数和结果的数据类型信息。
支持事务
- Pool:begin(),commit(),rollback()
- Connection:begin(),commit(),rollback()
使用示例
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扫描宏
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宏
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)
}
- 处理读取流
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(())
}
依赖项
~7–36MB
~571K SLoC