| 框架 | 协程异步async高并发 | 使用难度 | 同时支持Xml/Wrapper/内置增删改查 | logic del逻辑删除插件| page分页插件
| ------ | ------ |------ |------ |------ |------ |
| rbatis | √ | 非常简单 | √ | √ | √ |
| sqlx | √ | 难(强依赖宏和 莫名其妙的环境变量) | x | x | x |
| diesel | x | 简单(缺xml支持) | x | x | x |
| 框架 | Mysql(docker) | SQL语句(1万次) | 纳秒/每操作(低越好) | Qps(高越好) |内存消耗(低越好) |
| ------ | ------ |------ |------ |------ |------ |
| Rust语言-rbatis/tokio | 1CPU,1G内存 | select count(1) from table; | 965649 ns/op | 1035 Qps/s | 2.1MB |
| Go语言-GoMybatis/http | 1CPU,1G内存 | select count(1) from table; | 1184503 ns/op | 844 Qps/s | 28.4MB |
``` rust
serde = { version = "1.0", features = ["derive"] } serde_json = "1.0"
chrono = { version = "0.4", features = ["serde"] }
log = "0.4" fast_log="1.2.2"
bigdecimal = "0.2"
rbatis-core = { version = "1.6.0", features = ["all"]} rbatis = { version = "1.6.0" } rbatis-macro-driver = { version = "1.6.0" }
```
```rust
extern crate rbatismacrodriver; ///数据库表模型 CRUDEnable也可以写成 impl CRUDEnable for BizActivity{}
pub struct BizActivity {
pub id: Option
// (可选) 手动实现,不使用上面的derive(CRUDEnable),可重写tablename方法。手动实现能支持IDE智能提示
//impl CRUDEnable for BizActivity {
// type IdType = String;
// fn tablename()->String{
// "bizactivity".tostring()
// }
// fn tablefields()->String{
// "id,name,deleteflag".to_string()
// }
//}
async fn main() {
///rbatis初始化,rbatis是线程安全可使用lazystatic 定义为全局变量
let rb = Rbatis::new();
///连接数据库
rb.link("mysql://root:123456@localhost:3306/test").await.unwrap();
///自定义连接池参数。(可选)
// let mut opt =PoolOptions::new();
// opt.maxsize=100;
// rb.linkopt("mysql://root:123456@localhost:3306/test",&opt).await.unwrap();
///新建的wrapper sql逻辑
let wrapper = rb.newwrapper()
.eq("id", 1) //sql: id = 1
.and() //sql: and
.ne("id", 1) //sql: id <> 1
.inarray("id", &[1, 2, 3]) //sql: id in (1,2,3)
.notin("id", &[1, 2, 3]) //sql: id not in (1,2,3)
.like("name", 1) //sql: name like 1
.or() //sql: or
.notlike("name", "asdf") //sql: name not like 'asdf'
.between("createtime", "2020-01-01 00:00:00", "2020-12-12 00:00:00")//sql: createtime between '2020-01-01 00:00:00' and '2020-01-01 00:00:00'
.groupby(&["id"]) //sql: group by id
.order_by(true, &["id", "name"])//sql: group by id,name
.check().unwrap();
let activity = BizActivity { id: Some("12312".tostring()), name: None, remark: None, createtime: Some(NaiveDateTime::now()), version: Some(1), deleteflag: Some(1), }; ///保存 rb.save("",&activity).await; //Exec ==> INSERT INTO bizactivity (createtime,deleteflag,h5bannerimg,h5link,id,name,pcbannerimg,pclink,remark,sort,status,version) VALUES ( ? , ? , ? , ? , ? , ? , ? , ? , ? , ? , ? , ? )
///批量保存 rb.savebatch("", &vec![activity]).await; //Exec ==> INSERT INTO bizactivity (createtime,deleteflag,h5bannerimg,h5link,id,name,pcbannerimg,pclink,remark,sort,status,version) VALUES ( ? , ? , ? , ? , ? , ? , ? , ? , ? , ? , ? , ? ),( ? , ? , ? , ? , ? , ? , ? , ? , ? , ? , ? , ? )
///查询, Option包装,有可能查不到数据则为None
let result: Option
///查询-全部
let result: Vec
///批量-查询id
let result: Vec
///自定义查询 let w = rb.newwrapper().eq("id", "1").check().unwrap(); let r: Resultbywrapper("", &w).await; //Query ==> SELECT createtime,deleteflag,h5bannerimg,h5link,id,name,pcbannerimg,pclink,remark,sort,status,version FROM bizactivity WHERE delete_flag = 1 AND id = ?
///删除
rb.removebyid::
///批量删除
rb.removebatchbyid::
///修改 let w = rb.newwrapper().eq("id", "12312").check().unwrap(); rb.updatebywrapper("", &activity, &w).await; //Exec ==> UPDATE bizactivity SET createtime = ? , deleteflag = ? , status = ? , version = ? WHERE id = ? }
///...还有更多方法,请查看crud.rs ```
```rust lazy_static! { static ref RB:Rbatis=Rbatis::new(); }
/// 宏根据方法定义生成执行逻辑,又点类似于 java/mybatis的@select动态sql
/// RB是本地依赖Rbatis引用的名称,例如 dao::RB, com::xxx::RB....都可以
/// 第二个参数是标准的驱动sql,注意对应数据库参数mysql为?,pg为$1...
/// 宏会自动转换函数为 pub async fn select(name: &str) -> rbatis_core::Result<BizActivity> {}
///
#[sql(RB, "select * from biz_activity where id = ?")]
fn select(name: &str) -> BizActivity {}
//其他写法: pub async fn select(name: &str) -> rbatis_core::Result<BizActivity> {}
#[async_std::test]
pub async fn test_macro() {
fast_log::log::init_log("requests.log", &RuntimeType::Std);
RB.link("mysql://root:123456@localhost:3306/test").await.unwrap();
let a = select("1").await.unwrap();
println!("{:?}", a);
}
rust
lazy_static! {
static ref RB:Rbatis=Rbatis::new();
}
/// 宏根据方法定义生成执行逻辑,又点类似于 java/mybatis的@select动态sql
/// RB是本地依赖Rbatis引用的名称,例如 dao::RB, com::xxx::RB....都可以
/// 第二个参数是标准的驱动sql,注意对应数据库参数mysql为?,pg为$1...
/// 宏会自动转换函数为 pub async fn select(name: &str) -> rbatis_core::Result<BizActivity> {}
///
#[py_sql(RB, "select * from biz_activity where id = #{name}
if name != '':
and name=#{name}")]
fn py_select(name: &str) -> Option<BizActivity> {}
//其他写法: pub async fn select(name: &str) -> rbatis_core::Result<BizActivity> {}
#[async_std::test]
pub async fn test_macro_py_select() {
fast_log::log::init_log("requests.log", &RuntimeType::Std);
RB.link("mysql://root:123456@localhost:3306/test").await.unwrap();
let a = py_select("1").await.unwrap();
println!("{:?}", a);
}
```
rust
let mut rb = init_rbatis().await;
//rb.logic_plugin = Some(Box::new(RbatisLogicDeletePlugin::new_opt("delete_flag",1,0)));//自定义已删除/未删除 写法
rb.logic_plugin = Some(Box::new(RbatisLogicDeletePlugin::new("delete_flag")));
rb.link("mysql://root:123456@localhost:3306/test").await.unwrap();
let r = rb.remove_batch_by_id::<BizActivity>("", &["1".to_string(), "2".to_string()]).await;
if r.is_err() {
println!("{}", r.err().unwrap().to_string());
}
```rust let mut rb = Rbatis::new(); rb.link("mysql://root:123456@localhost:3306/test").await.unwrap(); //框架默认RbatisPagePlugin,如果需要自定义的话需要结构体 必须实现impl PagePlugin for Plugin*{},例如: //rb.page_plugin = Box::new(RbatisPagePlugin {});
let req = PageRequest::new(1, 20);//分页请求,页码,条数
let wraper= rb.new_wrapper()
.eq("delete_flag",1)
.check()
.unwrap();
let data: Page<BizActivity> = rb.fetch_page_by_wrapper("", &wraper, &req).await.unwrap();
println!("{}", serde_json::to_string(&data).unwrap());
//2020-07-10T21:28:40.036506700+08:00 INFO rbatis::rbatis - [rbatis] Query ==> SELECT count(1) FROM bizactivity WHERE deleteflag = ? LIMIT 0,20
//2020-07-10T21:28:40.040505200+08:00 INFO rbatis::rbatis - [rbatis] Args ==> [1]
//2020-07-10T21:28:40.073506+08:00 INFO rbatis::rbatis - [rbatis] Total <== 1
//2020-07-10T21:28:40.073506+08:00 INFO rbatis::rbatis - [rbatis] Query ==> SELECT createtime,deleteflag,h5bannerimg,h5link,id,name,pcbannerimg,pclink,remark,sort,status,version FROM bizactivity WHERE deleteflag = ? LIMIT 0,20
//2020-07-10T21:28:40.073506+08:00 INFO rbatis::rbatis - [rbatis] Args ==> [1]
//2020-07-10T21:28:40.076506500+08:00 INFO rbatis::rbatis - [rbatis] Total <== 5
json
{
"records": [{
"id": "12312",
"name": "null",
"pclink": "null",
"h5link": "null",
"pcbannerimg": "null",
"h5bannerimg": "null",
"sort": "null",
"status": 1,
"remark": "null",
"createtime": "2020-02-09T00:00:00+00:00",
"version": 1,
"deleteflag": 1
}],
"total": 5,
"size": 20,
"current": 1,
"serch_count": true
}
```
python
//执行到远程mysql 并且获取结果。支持serde_json可序列化的任意类型
let rb = Rbatis::new();
rb.link("mysql://root:123456@localhost:3306/test").await.unwrap();
let py = r#"
SELECT * FROM biz_activity
WHERE delete_flag = #{delete_flag}
if name != null:
AND name like #{name+'%'}
if ids != null:
AND id in (
trim ',':
for item in ids:
#{item},
)"#;
let data: serde_json::Value = rb.py_fetch("", py, &json!({ "delete_flag": 1 })).await.unwrap();
println!("{}", data);
rust
//main函数加入
use log::{error, info, warn};
fn main(){
fast_log::log::init_log("requests.log", &RuntimeType::Std).unwrap();
info!("print data");
}
```rust use rbatis_core::db::PoolOptions;
pub async fn initrbatis() -> Rbatis { let rb = Rbatis::new(); let mut opt = PoolOptions::new(); opt.maxsize = 20; rb.link_opt("mysql://root:123456@localhost:3306/test", &opt).await.unwrap(); } ```
``` rust /** * 数据库表模型 */
pub struct Activity {
pub id: Option
let arg = &json!({
"delete_flag": 1,
"name": "test",
"startTime": null,
"endTime": null,
"page": 0,
"size": 20
});
let data: Vec<BizActivity> = rb.xml_fetch("", "test", "select_by_condition", arg).await.unwrap();
println!("{}", serde_json::to_string(&data).unwrap_or("".to_string()));
}
)
} //输出结果 //2020-06-27T03:13:40.422307200+08:00 INFO rbatis::rbatis - [rbatis] >> fetch sql: select * from bizactivity where name like ? order by createtime desc limit ? , ? (src\rbatis.rs:198) //2020-06-27T03:13:40.424307300+08:00 INFO rbatis::rbatis - [rbatis] >> fetch arg:["%test%",0,20] (src\rbatis.rs:199) //2020-06-27T03:13:40.446308900+08:00 INFO rbatis::rbatis - [rbatis] << 4 (src\rbatis.rs:234) //[{"id":"221","name":"test","pclink":"","h5link":"","pcbannerimg":null,"h5bannerimg":null,"sort":"0","status":0,"remark":"","createtime":"2020-06-17T20:10:23Z","version":0,"deleteflag":1},{"id":"222","name":"test","pclink":"","h5link":"","pcbannerimg":null,"h5bannerimg":null,"sort":"0","status":0,"remark":"","createtime":"2020-06-17T20:10:23Z","version":0,"deleteflag":1},{"id":"223","name":"test","pclink":"","h5link":"","pcbannerimg":null,"h5bannerimg":null,"sort":"0","status":0,"remark":"","createtime":"2020-06-17T20:10:23Z","version":0,"deleteflag":1},{"id":"178","name":"testinsret","pclink":"","h5link":"","pcbannerimg":null,"h5bannerimg":null,"sort":"1","status":1,"remark":"","createtime":"2020-06-17T20:08:13Z","version":0,"delete_flag":1}] ```
rust
async_std::task::block_on(async {
let rb = Rbatis::new();
rb.link("mysql://root:123456@localhost:3306/test").await.unwrap();
let tx_id = "1";//事务id号
rb.begin(tx_id).await.unwrap();
let v: serde_json::Value = rb.fetch(tx_id, "SELECT count(1) FROM biz_activity;").await.unwrap();
println!("{}", v.clone());
rb.commit(tx_id).await.unwrap();
});
``` rust lazy_static! { static ref RB:Rbatis=Rbatis::new(); }
async fn index() -> impl Responder {
let v:Result
async fn main() -> std::io::Result<()> { //日志 fastlog::log::initlog("requests.log", &RuntimeType::Std).unwrap(); //链接数据库 RB.link("mysql://root:123456@localhost:3306/test").await.unwrap(); //http路由 HttpServer::new(|| { App::new() .route("/", web::get().to(index)) }) .bind("127.0.0.1:8000")? .run() .await } ```
| 数据库 | 已支持 |
| ------ | ------ |
| Option | √ |
| Vec | √ |
| HashMap | √ |
| Slice | √ |
| i32,i64,f32,f64,bool,String...more rust type | √ |
| NativeDateTime | √ |
| BigDecimal | √ |
| serde_json::Value...more serde type | √ |
| 数据库 | 已支持 |
| ------ | ------ |
| Mysql | √ |
| Postgres | √ |
| Sqlite | √ |
| TiDB | √ |
| CockroachDB | √ |
| 平台 | 已支持 |
| ------ | ------ |
| Linux | √ |
| Apple/MacOS | √ |
| Windows | √ |
| 功能 | 已支持 |
| ------ | ------ |
| CRUD(内置CRUD模板(内置CRUD支持逻辑删除插件)) | √ |
| LogSystem(日志组件) | √ |
| Tx(事务/事务嵌套/注解声明式事务) | √ |
| Py(在SQL中使用和xml等价的类python语法) | √ |
| SlowSqlCount(内置慢查询日志分析) | √ |
| async/await支持 | √ |
| PagePlugin(分页插件) | √ |
| LogicDelPlugin(逻辑删除插件) | √ |
| DataBaseConvertPlugin(数据库表结构转换为配置插件) | x |
| web(可视化Web UI) | x |
``` //sql构建性能 ExampleActivityMapper.xml -> selectby_condition 操作/纳秒nano/op: 0.202 s,each:2020 nano/op 事务数/秒 TPS: 495049.50495049503 TPS/s
//查询结果解码性能 decode/mysqljsondecoder -> benchdecodemysql_json 操作/纳秒nano/op: 0.24 s,each:2400 nano/op 事务数/秒 TPS: 416666.6666666667 TPS/s
//综合性能约等于 操作/纳秒nano/op: 4420 nano/op 事务数/秒 TPS: 200000 TPS/s ```
rbatis-core = { features = ["runtime-async-std","all-type"]}
```