A ORM formwork Rustlang-based,dynamic sql, no Runtime,No Garbage Collector, low Memory use,High Performance orm Framework.

rbatis 是一个无GC无虚拟机无运行时Runtime直接编译为机器码,并发安全的 数据库 ORM框架,并且所有数据传值均使用json(serde_json)

rbatis 使用百分之百的安全代码实现

This crate uses #![forbid(unsafe_code)] to ensure everything is implemented in 100% Safe Rust.

Build Status

Image text

首先(Cargo.toml)添加项目依赖

``` rust

add this library,and cargo install

json

serde = { version = "1.0", features = ["derive"] } serde_json = "1.0"

log

log = "0.4" fast_log="1.0.2"

rbatis-core和rbatis 版本必须保持一致

rbatis-core = { version = "1.2.0", default-features = false , features = ["all","runtime-async-std"]} rbatis = "1.2.0" ```

基本的CRUD内置方法 save,savebatch,removebatchbyid,listbyids...等等常用方法(详见 example/crud_test.rs)

rust let activity = Activity { id: Some("12312".to_string()), name: None, remark: None, create_time: Some("2020-02-09 00:00:00".to_string()), version: Some(1), delete_flag: Some(1), }; let r = rb.save(&activity).await; if r.is_err() { println!("{}", r.err().unwrap().to_string()); }

QueryWrapper支持,可以免写xml,py,sql(详见 example/crud_test.rs)

rust let mut m = Map::new(); m.insert("a".to_string(), json!("1")); let w = Wrapper::new(&DriverType::Mysql).eq("id", 1) .and() .ne("id", 1) .and() .in_array("id", &[1, 2, 3]) .and() .not_in("id", &[1, 2, 3]) .and() .all_eq(&m) .and() .like("name", 1) .or() .not_like("name", "asdf") .and() .between("create_time", "2020-01-01 00:00:00", "2020-12-12 00:00:00") .group_by(&["id"]) .order_by(true, &["id", "name"]) .check().unwrap();

py风格sql语法Example

python //执行到远程mysql 并且获取结果。支持serde_json可序列化的任意类型 let rb = Rbatis::new(MYSQL_URL).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);

日志系统(这里举例使用fast_log)

rust //main函数加入 use log::{error, info, warn}; fn main(){ fast_log::log::init_log("requests.log", &RuntimeType::Std).unwrap(); info!("print data"); }

xml使用方法

``` rust /** * 数据库表模型 */

[derive(Serialize, Deserialize, Debug, Clone)]

pub struct Activity { pub id: Option, pub name: Option, pub pclink: Option, pub h5link: Option, pub pcbannerimg: Option, pub h5bannerimg: Option, pub sort: Option, pub status: Option, pub remark: Option, pub createtime: Option>, pub version: Option, pub deleteflag: Option, } fn main() { asyncstd::task::blockon( async move { fastlog::log::initlog("requests.log", &RuntimeType::Std).unwrap(); let mut rb = Rbatis::new(); rb.link(MYSQLURL).await.unwrap(); //xml数据建议以 XXMapper.xml 的格式存储管理 rb.loadxml("test", r#" "#).unwrap();

           let arg = &json!({
           "delete_flag": 1,
           "name": "test",
           "startTime": null,
           "endTime": null,
           "page": 0,
           "size": 20
           });
           let data: Vec<Activity> = 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(MYSQL_URL).await.unwrap(); let tx_id = "1"; 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(); });

Web框架支持(这里举例hyper)

``` rust

lazystatic! { static ref RB:Rbatis<'static>=asyncstd::task::blockon(async { Rbatis::new(MYSQLURL).await.unwrap() }); }

use std::convert::Infallible; async fn hello(: hyper::Request) -> Result, Infallible> { let v = RB.fetch("", "SELECT count(1) FROM bizactivity;").await; if v.isok() { let data: Value = v.unwrap(); Ok(hyper::Response::new(hyper::Body::from(data.tostring()))) } else { Ok(hyper::Response::new(hyper::Body::from(v.err().unwrap().to_string()))) } }

[tokio::main]

[test]

pub async fn testhyper(){ fastlog::log::initlog("requests.log",&RuntimeType::Std); // For every connection, we must make a Service to handle all // incoming HTTP requests on said connection. let makesvc = hyper::service::makeservicefn(|conn| { // This is the Service that will handle the connection. // service_fn is a helper to convert a function that // returns a Response into a Service. async { Ok::<_, Infallible>(hyper::service::servicefn(hello)) } }); let addr = ([0, 0, 0, 0], 8000).into(); let server = hyper::Server::bind(&addr).serve(make_svc); println!("Listening on http://{}", addr); server.await.unwrap(); } ```

支持数据库类型√已支持.进行中

| 数据库 | 已支持 | | ------ | ------ | | Mysql | √ |
| Postgres | √ |
| Sqlite | √ |
| TiDB | √ | | CockroachDB | √ |

进度表-按照顺序实现

| 功能 | 已支持 | | ------ | ------ | | CRUD(内置CRUD模板(内置CRUD支持乐观锁/逻辑删除)) | √ | | LogSystem(日志组件) | √ | | Tx(事务/事务嵌套/注解声明式事务) | √ |
| Py(在SQL中使用和xml等价的类python语法) | √ | | SlowSqlCount(内置慢查询日志分析) | √ | | async/await支持 | √ | | PagePlugin(分页插件) | √ | | LogicDelPlugin(逻辑删除插件) | x | | VersionLockPlugin(乐观锁插件,防止并发修改数据) | x | | DataBaseConvertPlugin(数据库表结构转换为配置插件) | x | | web(可视化Web UI) | x |

基准测试benchmark (测试平台 win10,6 core i7,16GB)

分步骤压测

``` //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"]}

或者Cargo.toml 加入

rbatis-core = { features = ["runtime-tokio","all-type"]}

```

和Rbatis相关项目

TODO 即将到来的特性

欢迎右上角star或者微信捐赠~

Image text