通用ORM的設計與實現

語言: CN / TW / HK

介紹

我們通用的ORM,基本模式都是想要脫離資料庫的,幾乎都在程式語言層面建立模型,由程式去與資料庫打交道。雖然脫離了資料庫的具體操作,但我們要建立各種模型文件,用程式碼去寫表之間的關係等等操作,讓初學者一時如墜雲霧。我的想法是,將關係資料庫擁有的完善設計工具之優勢,來實現資料設計以提供結構資訊,讓json物件自動對映成為標準的SQL查詢語句。只要我們理解了標準的SQL語言,我們就能夠完成資料庫查詢操作。

依賴關係

本專案依賴 本人的 另一個專案 Zjson,此專案提供簡潔、方便、高效的Json庫。該庫使用方便,是一個單檔案庫,只需要下載並引入專案即可。具體資訊請移步gitee-Zjson 或github-Zjson 。

設計思路

ZORM 資料傳遞採用json來實現,使資料標準能從最前端到最後端達到和諧統一。此專案目標,不但在要C++中使用,還要作為動態連結庫與node.js結合用使用,因此希望能像javascript一樣,簡潔方便的操作json。所以先行建立了zjson庫,作為此專案的先行專案。設計了資料庫通用操作介面,實現與底層實現資料庫的分離。該介面提供了CURD標準訪問,以及批量插入和事務操作,基本能滿足平時百分之九十以上的資料庫操作。專案基本目標,支援Sqlite3,Mysql,Postges三種關係資料庫,同時支援windows、linux和macOS。

專案進度

現在已經實現了sqlit3與mysql的所有功能,postgres也做了技術準備。

我選擇的技術實現方式,基本上是最底層高效的方式。sqlit3 - sqllit3.h(官方的標準c介面);mysql - c api (MySQL Connector C 6.1);postgres - pqxx 。

任務列表:

  • [x] Sqlite3 實現

    • [x] linux
    • [x] windows
    • [x] macos
  • [x] Mysql 實現

    • [x] linux
    • [x] windows
    • [x] macos
  • [ ] Pstgre 實現

    • [ ] linux
    • [ ] windows
    • [ ] macos

資料庫通用介面

應用類直接操作這個通用介面,實現與底層實現資料庫的分離。該介面提供了CURD標準訪問,以及批量插入和事務操作,基本能滿足平時百分之九十以上的資料庫操作。

class ZORM_API Idb
  {
  public:
      virtual Json select(string tablename, Json& params, vector<string> fields = vector<string>(), Json values = Json(JsonType::Array)) = 0;
      virtual Json create(string tablename, Json& params) = 0;
      virtual Json update(string tablename, Json& params) = 0;
      virtual Json remove(string tablename, Json& params) = 0;
      virtual Json querySql(string sql, Json params = Json(), Json values = Json(JsonType::Array), vector<string> fields = vector<string>()) = 0;
      virtual Json execSql(string sql, Json params = Json(), Json values = Json(JsonType::Array)) = 0;
      virtual Json insertBatch(string tablename, Json& elements, string constraint = "id") = 0;
      virtual Json transGo(Json& sqls, bool isAsync = false) = 0;
  };

例項構造

全域性查詢開關變數:

  • DbLogClose : sql 查詢語句顯示開關
  • parameterized : 是否使用引數化查詢

Sqlite3:

Json options;
    options.addSubitem("connString", "./db.db");    //資料庫位置
    options.addSubitem("DbLogClose", false);        //顯示查詢語句
    options.addSubitem("parameterized", false);     //不使用引數化查詢
    DbBase* db = new DbBase("sqlite3", options);

Mysql:

Json options;
    options.addSubitem("db_host", "192.168.6.6");   //mysql服務IP
    options.addSubitem("db_port", 3306);            //埠
    options.addSubitem("db_name", "dbtest");        //資料庫名稱
    options.addSubitem("db_user", "root");          //登記使用者名稱
    options.addSubitem("db_pass", "123456");        //密碼
    options.addSubitem("db_char", "utf8mb4");       //連線字元設定[可選]
    options.addSubitem("db_conn", 5);               //連線池配置[可選],預設為2
    options.addSubitem("DbLogClose", true);         //不顯示查詢語句
    options.addSubitem("parameterized", true);      //使用引數化查詢
    DbBase* db = new DbBase("mysql", options);

智慧查詢方式設計

查詢保留字:page, size, sort, fuzzy, lks, ins, ors, count, sum, group

  • page, size, sort, 分頁排序

    在sqlit3與mysql中這比較好實現,limit來分頁是很方便的,排序只需將引數直接拼接到order by後就好了。

    查詢示例:

    Json p;
    p.addSubitem("page", 1);
    p.addSubitem("size", 10);
    p.addSubitem("size", "sort desc");
    (new DbBase(...))->select("users", p);
    
    生成sql:   SELECT * FROM users  ORDER BY age desc LIMIT 0,10
  • fuzzy, 模糊查詢切換引數,不提供時為精確匹配

    提供欄位查詢的精確匹配與模糊匹配的切換。

    Json p;
    p.addSubitem("username", "john");
    p.addSubitem("password", "123");
    p.addSubitem("fuzzy", 1);
    (new DbBase(...))->select("users", p);
     
    生成sql:   SELECT * FROM users  WHERE username like '%john%'  and password like '%123%'
  • ins, lks, ors

    這是最重要的三種查詢方式,如何找出它們之間的共同點,減少冗餘程式碼是關鍵。

    • ins, 資料庫表單欄位in查詢,一欄位對多個值,例:

      查詢示例:

      Json p;
      p.addSubitem("ins", "age,11,22,36");
      (new DbBase(...))->select("users", p);
      
      生成sql:   SELECT * FROM users  WHERE age in ( 11,22,26 )
    • ors, 資料庫表多欄位精確查詢,or連線,多個欄位對多個值,例:

      查詢示例:

      Json p;
      p.addSubitem("ors", "age,11,age,36");
      (new DbBase(...))->select("users", p);
      
      生成sql:   SELECT * FROM users  WHERE  ( age = 11  or age = 26 )
    • lks, 資料庫表多欄位模糊查詢,or連線,多個欄位對多個值,例:

      查詢示例:

      Json p;
      p.addSubitem("lks", "username,john,password,123");
      (new DbBase(...))->select("users", p);
      
      生成sql:   SELECT * FROM users  WHERE  ( username like '%john%'  or password like '%123%'  )
  • count, sum

    這兩個統計求和,處理方式也類似,查詢時一般要配合group與fields使用。

    • count, 資料庫查詢函式count,行統計,例:

      查詢示例:

      Json p;
      p.addSubitem("count", "1,total");
      (new DbBase(...))->select("users", p);
      
      生成sql:   SELECT *,count(1) as total  FROM users
    • sum, 資料庫查詢函式sum,欄位求和,例:

      查詢示例:

      Json p;
      p.addSubitem("sum", "age,ageSum");
      (new DbBase(...))->select("users", p);
      
      生成sql:   SELECT username,sum(age) as ageSum  FROM users
  • group, 資料庫分組函式group,例:

    查詢示例:

    Json p;
    p.addSubitem("group", "age");
    (new DbBase(...))->select("users", p);
    
    生成sql:   SELECT * FROM users  GROUP BY age

不等操作符查詢支援

支援的不等操作符有:>, >=, <, <=, <>, =;逗號符為分隔符,一個欄位支援一或二個操作。

特殊處:使用"="可以使某個欄位跳過search影響,讓模糊匹配與精確匹配同時出現在一個查詢語句中

  • 一個欄位一個操作,示例:

    查詢示例:

    Json p;
    p.addSubitem("age", ">,10");
    (new DbBase(...))->select("users", p);
    
    生成sql:   SELECT * FROM users  WHERE age> 10
  • 一個欄位二個操作,示例:

    查詢示例:

    Json p;
    p.addSubitem("age", ">=,10,<=,33");
    (new DbBase(...))->select("users", p);
    
    生成sql:   SELECT * FROM users  WHERE age>= 10 and age<= 33
  • 使用"="去除欄位的fuzzy影響,示例:

    查詢示例:

    Json p;
    p.addSubitem("age", "=,18");
    p.addSubitem("username", "john");
    p.addSubitem("fuzzy", "1");
    (new DbBase(...))->select("users", p);
    
    生成sql:   SELECT * FROM users  WHERE age= 18  and username like '%john%'

    具體使用方法,請參看uint test。

單元測試

有完整功能的單元測試用例,請參見tests目錄下的測試用例。

測試用例執行結果樣例

專案地址

https://gitee.com/zhoutk/zorm
或
https://github.com/zhoutk/zorm

執行方法

該專案在vs2019, gcc7.5, clang12.0下均編譯執行正常。

git clone https://github.com/zhoutk/zorm
cd zorm
cmake -Bbuild .

---windows
cd build && cmake --build .

---linux & macos
cd build && make

run zorm or ctest

注在linux下需要先行安裝mysql開發庫, 並先手動建立資料庫 dbtest。

在ubuntu下的命令是: apt install libmysqlclient-dev

相關專案

會有一系列專案出爐,網路服務相關,敬請期待...