这等Java ORM的优雅设计,你难道没见识过吗?

2026-04-19 16:474阅读0评论SEO基础
  • 内容介绍
  • 相关推荐

本文共计1735个文字,预计阅读时间需要7分钟。

这等Java ORM的优雅设计,你难道没见识过吗?

Java的ORM框架种类繁多,但受限于Java语言的特性,大部分都不够优雅也不够简单,因此开发者往往只能另辟蹊径,自行构建轮子。以下通过一个示例代码了解ORM的大概原理,然后进一步解释其实现原理。

一、ORM示例代码

javapublic class User { private int id; private String name; private String email;

// 省略getter和setter方法}

public class UserMapper { public void insert(User user) { // 模拟数据库插入操作 System.out.println(Inserting user: + user.getName()); }}

二、ORM实现原理

1. 映射关系:ORM框架通过映射关系将Java对象与数据库表对应起来。在上面的示例中,`User`类与数据库中的`users`表对应。

2. SQL生成:根据Java对象的方法调用,ORM框架生成相应的SQL语句。例如,`insert`方法会生成INSERT语句。

3. 数据库操作:ORM框架将生成的SQL语句发送到数据库执行,并处理返回的结果。

4. 结果映射:ORM框架将数据库返回的结果映射回Java对象。例如,查询结果可以封装成`User`对象列表。

通过以上步骤,ORM框架实现了Java对象与数据库之间的交互。

  Java的ORM框架有很多,但由于Java语言的限制大部分都不够优雅也不够简单,所以作者只能另辟蹊径造轮子了。照旧先看示例代码了解个大概,然后再解释实现原理。

这等Java ORM的优雅设计,你难道没见识过吗?

一、ORM示例

1. Insert

public CompletableFuture<Void> insert() { var obj = new sys.entities.Demo("MyName"); //构造参数为主键 obj.Age = 100; //设置实体属性的值 return obj.saveAsync(); }

2. Update

更新单个实体(必须具备主键)

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."; }); }

3. Delete

删除单个实体(必须具备主键)

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(); }

4. Transaction

  由于作者讨厌隐式事务,所以事务命令必须显式指定。

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"); }

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> }

分页查询

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(一对多成员) }

EntityRef(一对一引用的实体成员)自动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) //多个可重复 .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将上述代码在编译发布服务模型时分析转换为最终的运行代码,具体过程如下:

1. jdt分析服务虚拟代码生成AST抽象语法树;
2. 遍历AST树,将实体对象的读写属性改写为getXXX(), setXXX();

var name = obj.Name; //读实体属性 obj.Name = "Rick"; //写实体属性

改写为:

var name = obj.getName(); obj.setName("Rick");

3. 遍历AST树,将查询相关方法的参数转换为运行时表达式;

public CompletableFuture<?> query(String key) { var q = new SqlQuery<sys.entities.Employee>(); q.where(e -> e.Manager.Name + "a" == key + "b"); return q.toListAsync(); }

转换为:

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. 根据服务模型使用到的实体模型生成相应实体的运行时代码;
5. 最后编译打包服务模型的字节码。

以上请参考源码的ServiceCodeGenerator及EntityCodeGenerator类。

三、性能与小结

  作者写了个简单查询的服务,测试配置为MacBook主机(wrk压测 + 数据库)->4核I7虚拟机(服务端),测试结果如下所示qps可达1万,已包括实体映射转换及序列化传输等所有开销。这里顺便提一下,由于框架是全异步的,所以没有使用传统的JDBC驱动,而是使用了jasync-sql(底层为Netty)来驱动数据库。

wrk -c200 -t2 -d20s -s post_bin.lua 10.211.55.8:8000/api Running 20s test @ 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

以上就是这么优雅的Java ORM没见过吧!的详细内容,更多关于java orm的资料请关注易盾网络其它相关文章!

本文共计1735个文字,预计阅读时间需要7分钟。

这等Java ORM的优雅设计,你难道没见识过吗?

Java的ORM框架种类繁多,但受限于Java语言的特性,大部分都不够优雅也不够简单,因此开发者往往只能另辟蹊径,自行构建轮子。以下通过一个示例代码了解ORM的大概原理,然后进一步解释其实现原理。

一、ORM示例代码

javapublic class User { private int id; private String name; private String email;

// 省略getter和setter方法}

public class UserMapper { public void insert(User user) { // 模拟数据库插入操作 System.out.println(Inserting user: + user.getName()); }}

二、ORM实现原理

1. 映射关系:ORM框架通过映射关系将Java对象与数据库表对应起来。在上面的示例中,`User`类与数据库中的`users`表对应。

2. SQL生成:根据Java对象的方法调用,ORM框架生成相应的SQL语句。例如,`insert`方法会生成INSERT语句。

3. 数据库操作:ORM框架将生成的SQL语句发送到数据库执行,并处理返回的结果。

4. 结果映射:ORM框架将数据库返回的结果映射回Java对象。例如,查询结果可以封装成`User`对象列表。

通过以上步骤,ORM框架实现了Java对象与数据库之间的交互。

  Java的ORM框架有很多,但由于Java语言的限制大部分都不够优雅也不够简单,所以作者只能另辟蹊径造轮子了。照旧先看示例代码了解个大概,然后再解释实现原理。

这等Java ORM的优雅设计,你难道没见识过吗?

一、ORM示例

1. Insert

public CompletableFuture<Void> insert() { var obj = new sys.entities.Demo("MyName"); //构造参数为主键 obj.Age = 100; //设置实体属性的值 return obj.saveAsync(); }

2. Update

更新单个实体(必须具备主键)

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."; }); }

3. Delete

删除单个实体(必须具备主键)

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(); }

4. Transaction

  由于作者讨厌隐式事务,所以事务命令必须显式指定。

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"); }

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> }

分页查询

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(一对多成员) }

EntityRef(一对一引用的实体成员)自动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) //多个可重复 .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将上述代码在编译发布服务模型时分析转换为最终的运行代码,具体过程如下:

1. jdt分析服务虚拟代码生成AST抽象语法树;
2. 遍历AST树,将实体对象的读写属性改写为getXXX(), setXXX();

var name = obj.Name; //读实体属性 obj.Name = "Rick"; //写实体属性

改写为:

var name = obj.getName(); obj.setName("Rick");

3. 遍历AST树,将查询相关方法的参数转换为运行时表达式;

public CompletableFuture<?> query(String key) { var q = new SqlQuery<sys.entities.Employee>(); q.where(e -> e.Manager.Name + "a" == key + "b"); return q.toListAsync(); }

转换为:

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. 根据服务模型使用到的实体模型生成相应实体的运行时代码;
5. 最后编译打包服务模型的字节码。

以上请参考源码的ServiceCodeGenerator及EntityCodeGenerator类。

三、性能与小结

  作者写了个简单查询的服务,测试配置为MacBook主机(wrk压测 + 数据库)->4核I7虚拟机(服务端),测试结果如下所示qps可达1万,已包括实体映射转换及序列化传输等所有开销。这里顺便提一下,由于框架是全异步的,所以没有使用传统的JDBC驱动,而是使用了jasync-sql(底层为Netty)来驱动数据库。

wrk -c200 -t2 -d20s -s post_bin.lua 10.211.55.8:8000/api Running 20s test @ 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

以上就是这么优雅的Java ORM没见过吧!的详细内容,更多关于java orm的资料请关注易盾网络其它相关文章!