Java的ORM框架有不少,但因爲Java語言的限制大部分都不夠優雅也不夠簡單,因此做者只能另闢蹊徑造輪子了。照舊先看示例代碼瞭解個大概,而後再解釋實現原理。java
public CompletableFuture<Void> insert() { var obj = new sys.entities.Demo("MyName"); //構造參數爲主鍵 obj.Age = 100; //設置實體屬性的值 return obj.saveAsync(); }
public CompletableFuture<Void> update(sys.entities.Demo obj) { obj.Age = 200; return obj.saveAsync(); }
public CompletableFuture<?> update() { var cmd = new SqlUpdateCommand<sys.entities.Demo>(); cmd.update(e -> e.City = "Wuxi"); //更新字段 cmd.update(e -> e.Age = e.Age + 1); //更新累加字段 cmd.where(e -> e.Name == "Johne"); //更新的條件 var outs = cmd.output(e -> e.Age); //更新的同時返回指定字段 return cmd.execAsync().thenApply(rows -> { System.out.println("更新記錄數: " + rows); System.out.println("返回的值: " + outs.get(0)); return "Done."; }); }
public CompletableFuture<Void> update(sys.entities.Demo obj) { obj.markDeleted(); //先標記爲刪除狀態 return obj.saveAsync(); //再調用保存方法 }
public CompletableFuture<?> delete() { var cmd = new SqlDeleteCommand<sys.entities.Demo>(); cmd.where(e -> e.Age < 0 || e.Age > 200); return cmd.execAsync(); }
因爲做者討厭隱式事務,因此事務命令必須顯式指定。sql
public CompletableFuture<?> transaction() { var obj1 = new sys.entities.Demo("Demo1"); obj1.Age = 11; var obj2 = new sys.entities.Demo("Demo2"); obj2.Age = 22; return DataStore.DemoDB.beginTransaction().thenCompose(txn -> { //開始事務 return obj1.saveAsync(txn) //事務保存obj1 .thenCompose(r -> obj2.saveAsync(txn)) //事務保存obj2 .thenCompose(r -> txn.commitAsync()); //遞交事務 }).thenApply(r -> "Done"); }
public CompletableFuture<?> query(String key) { var q = new SqlQuery<sys.entities.Demo>(); q.where(e -> e.Age > 10 && e.Age < 80); if (key != null) q.andWhere(e -> e.Name.contains(key)); //拼接條件 return q.toListAsync(); //返回List<sys.entities.Demo> }
public CompletableFuture<?> query(int pageSize, int pageIndex) { var q = new SqlQuery<sys.entities.Demo>(); return q.skip(pageSize * pageIndex) .take(pageSize) .toListAsync(); }
public CompletableFuture<?> query() { var q = new SqlQuery<sys.entities.Demo>(); return q.toListAsync(e -> new Object() { //返回List<匿名類> public final String Name = e.Name; //匿名類屬性 = 實體屬性表達式 public final int Age = e.Age + 10; public final String Father = e.Parent.Name; }).thenApply(appbox.data.JsonResult::new); }
public CompletableFuture<?> query() { var q = new SqlQuery<sys.entities.Demo>(); q.where(e -> e.Parent.Name == "Rick"); return q.toListAsync(e -> new sys.entities.Demo() { //返回List<? extens Demo> public final String Father = e.Parent.Name; }); }
public CompletableFuture<?> tree() { var q = new SqlQuery<sys.entities.Demo>(); q.where(t -> t.Name == "Rick"); return q.toTreeAsync(t -> t.Childs); //參數指向EntitySet(一對多成員) }
public CompletableFuture<?> query() { var q = new SqlQuery<sys.entities.Customer>(); q.where(cus -> cus.City.Name == "Wuxi"); return q.toListAsync(); } 生成的Sql: Select t.* From "Customer" t Left Join "City" j1 On j1."Code"=t."CityCode"
public CompletableFuture<?> join() { var q = new SqlQuery<sys.entities.Customer>(); var j = new SqlQueryJoin<sys.entities.City>(); q.leftJoin(j, (cus, city) -> cus.CityCode == city.Code); q.where(j, (cus, city) -> city.Name == "Wuxi"); return q.toListAsync(); }
public CompletableFuture<?> subQuery() { var sq = new SqlQuery<sys.entities.Demo>(); sq.where(s -> s.ParentName == "Rick"); var q = new SqlQuery<sys.entities.Demo>(); q.where(t -> DbFunc.in(t.Name, sq.toSubQuery(s -> s.Name))); return q.toListAsync(); }
public CompletableFuture<?> groupBy() { var q = new SqlQuery<sys.entities.Demo>(); q.groupBy(t -> t.ParentName) //多個可重複 .having(t -> DbFunc.sum(t.Age) > 10); return q.toListAsync(t -> new Object() { public final String group = t.ParentName == null ? "可憐的孩子" : t.ParentName; public final int totals = DbFunc.sum(t.Age); }).thenApply(appbox.data.JsonResult::new); }
其實以上的示例代碼並不是最終運行的代碼,做者利用Eclipse jdt將上述代碼在編譯發佈服務模型時分析轉換爲最終的運行代碼,具體過程以下:shell
var name = obj.Name; //讀實體屬性 obj.Name = "Rick"; //寫實體屬性
改寫爲:數據庫
var name = obj.getName(); obj.setName("Rick");
public CompletableFuture<?> query(String key) { var q = new SqlQuery<sys.entities.Employee>(); q.where(e -> e.Manager.Name + "a" == key + "b"); return q.toListAsync(); }
轉換爲:api
public CompletableFuture<?> query(String key) { var q = new appbox.store.query.SqlQuery<>(-7018111290459553788L, SYS_Employee.class); q.where(e -> e.m("Manager").m("Name").plus("a").eq(key + "b")); return q.toListAsync(); }
以上請參考源碼的ServiceCodeGenerator及EntityCodeGenerator類。app
做者寫了個簡單查詢的服務,測試配置爲MacBook主機(wrk壓測 + 數據庫)->4核I7虛擬機(服務端),測試結果以下所示qps可達1萬,已包括實體映射轉換及序列化傳輸等全部開銷。這裏順便提一下,因爲框架是全異步的,因此沒有使用傳統的JDBC驅動,而是使用了jasync-sql(底層爲Netty)來驅動數據庫。框架
wrk -c200 -t2 -d20s -s post_bin.lua http://10.211.55.8:8000/api Running 20s test @ http://10.211.55.8:8000/api 2 threads and 200 connections Thread Stats Avg Stdev Max +/- Stdev Latency 18.97ms 5.84ms 89.15ms 81.55% Req/Sec 5.32k 581.92 6.48k 65.00% 211812 requests in 20.02s, 36.76MB read Requests/sec: 10578.90 Transfer/sec: 1.84MB
邊碼代碼邊碼文實屬不易,做者須要您的支持請您多多點贊推薦!另歡迎感興趣的小夥伴加入咱們!異步