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

rbatis = "*" ```

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代码Example

xml <mapper> <result_map id="BaseResultMap"> <id column="id" property="id"/> <result column="name" property="name" lang_type="string"/> <result column="pc_link" property="pcLink" lang_type="string"/> <result column="h5_link" property="h5Link" lang_type="string"/> <result column="remark" property="remark" lang_type="string"/> <result column="version" property="version" lang_type="number" version_enable="true"/> <result column="create_time" property="createTime" lang_type="time"/> <result column="delete_flag" property="deleteFlag" lang_type="number" logic_enable="true" logic_undelete="1" logic_deleted="0"/> </result_map> <select id="select_by_condition" result_map="BaseResultMap"> <bind name="pattern" value="'%' + name + '%'"/> select * from biz_activity <where> <if test="name != null">and name like #{pattern}</if> <if test="startTime != null">and create_time >= #{startTime}</if> <if test="endTime != null">and create_time &lt;= #{endTime}</if> </where> order by create_time desc <if test="page != null and size != null">limit #{page}, #{size}</if> </select> </mapper>

Cargo.toml 加入以下代码

toml [dependencies] rbatis = "*" log = "0.4" fast_log="1.0.2"

简单使用

``` rust

fn main() { asyncstd::task::blockon(async move { fastlog::log::initlog("requests.log", &RuntimeType::Std).unwrap(); let rb = Rbatis::new(MYSQLURL).await.unwrap(); let py = r#" SELECT * FROM bizactivity WHERE deleteflag = #{deleteflag} if name != null: AND name like #{name+'%'} if ids != null: AND id in ( trim ',': for item in ids: #{item}, )"#; let data: serdejson::Value = rb.pyfetch("", py, &json!({ "delete_flag": 1 })).await.unwrap(); println!("{}", data); }); } ```

xml使用方法

``` rust use crate::core::rbatis::Rbatis; use serde_json::{json, Value, Number}; /** * 数据库表模型 */

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

pub struct Activity { pub id: Option, pub name: Option, pub version: Option, }

fn main() { fastlog::log::initlog("requests.log").unwrap();//1 启用日志(可选,不添加则不加载日志库) let mut rb = Rbatis::new("mysql://root:TEST@localhost:3306/test").await.unwrap();//2 初始化rbatis rb.loadxml("ExampleActivityMapper.xml".tostring(),fs::readtostring("./src/example/ExampleActivityMapper.xml").unwrap());//4 加载xml配置 let dataresult: Vec =rbatis.eval("".tostring(), "selectbycondition", &json!({ "name":null, "startTime":null, "endTime":null, "page":null, "size":null, })).unwrap(); println!("[rbatis] result==> {:?}",dataresult); } //输出结果 //2020-01-10T10:28:54.437167+08:00 INFO rbatis::core::rbatis - [rbatis] Query ==> ExampleActivityMapper.xml.selectbycondition: select * from bizactivity order by createtime desc //2020-01-10T10:28:54.437306+08:00 INFO rbatis::core::rbatis - [rbatis][args] ==> ExampleActivityMapper.xml.selectby_condition: //2020-01-10T10:28:54.552097+08:00 INFO rbatis::core::rbatis - [rbatis] ReturnRows <== 2 //[rbatis] result==> [Activity { id: Some("\"dfbdd779-5f70-4b8f-9921-a235a9c75b69\""), name: Some("\"新人专享\""), version: Some(6) }, Activity { id: Some("\"dfbdd779-5f70-4b8f-9921-c235a9c75b69\""), name: Some("\"新人专享\""), version: Some(6) }] ```

事务支持

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支持 | √ | | LogicDelPlugin(逻辑删除插件) | x | | VersionLockPlugin(乐观锁插件,防止并发修改数据) | x | | PagePlugin(分页插件) | 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 ```

常见问题

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

Image text