這么優(yōu)雅的Java ORM沒(méi)見(jiàn)過(guò)吧!
??Java的ORM框架有很多,但由于Java語(yǔ)言的限制大部分都不夠優(yōu)雅也不夠簡(jiǎn)單,所以作者只能另辟蹊徑造輪子了。照舊先看示例代碼了解個(gè)大概,然后再解釋實(shí)現(xiàn)原理。
一、ORM示例
1. Insert
public CompletableFuture<Void> insert() {
var obj = new sys.entities.Demo("MyName"); //構(gòu)造參數(shù)為主鍵
obj.Age = 100; //設(shè)置實(shí)體屬性的值
return obj.saveAsync();
}
2. Update
- 更新單個(gè)實(shí)體(必須具備主鍵)
public CompletableFuture<Void> update(sys.entities.Demo obj) {
obj.Age = 200;
return obj.saveAsync();
}
- 根據(jù)條件更新(必須指定條件以防誤操作)
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); //更新的同時(shí)返回指定字段
return cmd.execAsync().thenApply(rows -> {
System.out.println("更新記錄數(shù): " + rows);
System.out.println("返回的值: " + outs.get(0));
return "Done.";
});
}
3. Delete
- 刪除單個(gè)實(shí)體(必須具備主鍵)
public CompletableFuture<Void> update(sys.entities.Demo obj) {
obj.markDeleted(); //先標(biāo)記為刪除狀態(tài)
return obj.saveAsync(); //再調(diào)用保存方法
}
- 根據(jù)條件刪除(必須指定條件以防誤操作)
public CompletableFuture<?> delete() {
var cmd = new SqlDeleteCommand<sys.entities.Demo>();
cmd.where(e -> e.Age < 0 || e.Age > 200);
return cmd.execAsync();
}
4. Transaction
??由于作者討厭隱式事務(wù),所以事務(wù)命令必須顯式指定。
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 -> { //開(kāi)始事務(wù)
return obj1.saveAsync(txn) //事務(wù)保存obj1
.thenCompose(r -> obj2.saveAsync(txn)) //事務(wù)保存obj2
.thenCompose(r -> txn.commitAsync()); //遞交事務(wù)
}).thenApply(r -> "Done");
}
5. Sql查詢
- Where條件
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>
}
- 分頁(yè)查詢
public CompletableFuture<?> query(int pageSize, int pageIndex) {
var q = new SqlQuery<sys.entities.Demo>();
return q.skip(pageSize * pageIndex)
.take(pageSize)
.toListAsync();
}
- 結(jié)果映射至匿名類
public CompletableFuture<?> query() {
var q = new SqlQuery<sys.entities.Demo>();
return q.toListAsync(e -> new Object() { //返回List<匿名類>
public final String Name = e.Name; //匿名類屬性 = 實(shí)體屬性表達(dá)式
public final int Age = e.Age + 10;
public final String Father = e.Parent.Name;
}).thenApply(appbox.data.JsonResult::new);
}
- 結(jié)果映射至繼承的匿名類
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;
});
}
- 結(jié)果映射至樹(shù)狀結(jié)構(gòu)列表
public CompletableFuture<?> tree() {
var q = new SqlQuery<sys.entities.Demo>();
q.where(t -> t.Name == "Rick");
return q.toTreeAsync(t -> t.Childs); //參數(shù)指向EntitySet(一對(duì)多成員)
}
- EntityRef(一對(duì)一引用的實(shí)體成員)自動(dòng)Join
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"
- 手工指定Join
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();
}
- GroupBy
public CompletableFuture<?> groupBy() {
var q = new SqlQuery<sys.entities.Demo>();
q.groupBy(t -> t.ParentName) //多個(gè)可重復(fù)
.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);
}
二、實(shí)現(xiàn)原理
??其實(shí)以上的示例代碼并非最終運(yùn)行的代碼,作者利用Eclipse jdt將上述代碼在編譯發(fā)布服務(wù)模型時(shí)分析轉(zhuǎn)換為最終的運(yùn)行代碼,具體過(guò)程如下:
1. jdt分析服務(wù)虛擬代碼生成AST抽象語(yǔ)法樹(shù);
2. 遍歷AST樹(shù),將實(shí)體對(duì)象的讀寫屬性改寫為getXXX(), setXXX();
var name = obj.Name; //讀實(shí)體屬性
obj.Name = "Rick"; //寫實(shí)體屬性
改寫為:
var name = obj.getName();
obj.setName("Rick");
3. 遍歷AST樹(shù),將查詢相關(guān)方法的參數(shù)轉(zhuǎn)換為運(yùn)行時(shí)表達(dá)式;
public CompletableFuture<?> query(String key) {
var q = new SqlQuery<sys.entities.Employee>();
q.where(e -> e.Manager.Name + "a" == key + "b");
return q.toListAsync();
}
轉(zhuǎn)換為:
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();
}
4. 根據(jù)服務(wù)模型使用到的實(shí)體模型生成相應(yīng)實(shí)體的運(yùn)行時(shí)代碼;
5. 最后編譯打包服務(wù)模型的字節(jié)碼。
以上請(qǐng)參考源碼的ServiceCodeGenerator及EntityCodeGenerator類。
三、性能與小結(jié)
??作者寫了個(gè)簡(jiǎn)單查詢的服務(wù),測(cè)試配置為MacBook主機(jī)(wrk壓測(cè) + 數(shù)據(jù)庫(kù))->4核I7虛擬機(jī)(服務(wù)端),測(cè)試結(jié)果如下所示qps可達(dá)1萬(wàn),已包括實(shí)體映射轉(zhuǎn)換及序列化傳輸?shù)人虚_(kāi)銷。這里順便提一下,由于框架是全異步的,所以沒(méi)有使用傳統(tǒng)的JDBC驅(qū)動(dòng),而是使用了jasync-sql(底層為Netty)來(lái)驅(qū)動(dòng)數(shù)據(jù)庫(kù)。
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
邊碼代碼邊碼文實(shí)屬不易,作者需要您的支持請(qǐng)您多多點(diǎn)贊推薦!另歡迎感興趣的小伙伴加入我們!

浙公網(wǎng)安備 33010602011771號(hào)