惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

N
News and Events Feed by Topic
D
DataBreaches.Net
Cyber Security Advisories - MS-ISAC
Cyber Security Advisories - MS-ISAC
Recorded Future
Recorded Future
Y
Y Combinator Blog
C
Check Point Blog
Google DeepMind News
Google DeepMind News
M
MIT News - Artificial intelligence
小众软件
小众软件
F
Full Disclosure
S
SegmentFault 最新的问题
Blog — PlanetScale
Blog — PlanetScale
B
Blog RSS Feed
Martin Fowler
Martin Fowler
P
Proofpoint News Feed
博客园 - 司徒正美
量子位
The GitHub Blog
The GitHub Blog
T
The Blog of Author Tim Ferriss
T
Tenable Blog
P
Privacy International News Feed
T
The Exploit Database - CXSecurity.com
C
Cyber Attacks, Cyber Crime and Cyber Security
Threat Intelligence Blog | Flashpoint
Threat Intelligence Blog | Flashpoint
G
Google Developers Blog
P
Proofpoint News Feed
T
Threatpost
Know Your Adversary
Know Your Adversary
aimingoo的专栏
aimingoo的专栏
Latest news
Latest news
Security Latest
Security Latest
Cyberwarzone
Cyberwarzone
A
About on SuperTechFans
P
Palo Alto Networks Blog
Stack Overflow Blog
Stack Overflow Blog
奇客Solidot–传递最新科技情报
奇客Solidot–传递最新科技情报
The Hacker News
The Hacker News
A
Arctic Wolf
AWS News Blog
AWS News Blog
C
CXSECURITY Database RSS Feed - CXSecurity.com
NISL@THU
NISL@THU
Last Week in AI
Last Week in AI
Hacker News - Newest:
Hacker News - Newest: "LLM"
Spread Privacy
Spread Privacy
OSCHINA 社区最新新闻
OSCHINA 社区最新新闻
freeCodeCamp Programming Tutorials: Python, JavaScript, Git & More
Application and Cybersecurity Blog
Application and Cybersecurity Blog
I
InfoQ
J
Java Code Geeks
H
Help Net Security

Java

华为的毕昇 JDK 8 AppCDS 特性稳定吗? - V2EX 我把 Java 开发的 kkRepo 支持 AOT 编译, 1s 极速启动,空闲内存小于 200MB - V2EX fastjson1.x 最新版本疑似又出 RCE 漏洞了 - V2EX 讲讲我怎么获得 kkRepo 的首个企业用户,成功替换掉 Nexus,每年节省 $1,620 PRO 订阅费用 - V2EX Sonatype 正引入 Maven Central 仓库发布使用情况可见性和针对高流量发布活动的限制 - V2EX 让 Java 再次伟大,没有人比我更懂得如何打包!(分享一个四两拨千斤的多 jar 打包 exe 方式) - V2EX 使用 kkRepo 搭建 Maven 私服 - V2EX Nexus 的平替 neuxs-plus 开源涉嫌商标侵权,被迫改名 kkRepo - V2EX 我在 IDEA tab 里养了一只猫 - V2EX Java 确实是内存高效的 用 AI 把 visualvm 的部分功能界面换了个马甲 - V2EX javaer 现在出去面试 问哪些内容 sa-token + spring cloud gateway 过滤器顺序问题 - V2EX 关于在 wsl 中使用 idea 进行 Java 开发的问题 - V2EX 求助, Fortify 漏扫问题解决 - V2EX 微信 ClawBot 和企微 AIBot 的 Java SDK - V2EX 老业务信创重构选型大家有啥建议 - V2EX ai 编程的情况在你们使用什么 IDE - V2EX 下面这段 Java 多态的代码,如何才能改为 Go、 Python 、JS、C++版本? - V2EX JDK 26 发布,非 lts 版本 - V2EX 求推荐比较优秀的 springboot 脚手架项目 - V2EX vscode 里自用 Java 开发插件:支持复制引用路径、rest 接口路径、Arthas 命令等功能 - V2EX 自荐 Java 多线程神器——ThreadForge ,让多线程从此简单 - V2EX 屎山老项目想用 ai 实现自动化测试,有什么可落地的方案么 - V2EX WebFlux 项目 被访问后 访问方关闭连接 无法捕获 SocketException: Connection reset - V2EX 有人用 RUOYI 框架吗? - V2EX 关于商用 jdk 收费的问题,有遥测吗? - V2EX IDEA 在 macOS 上卡住 - V2EX Java : 2026 年 SpringBoot, Quarkus, Solon ? - V2EX 佬们有没有比较好的 Java 脚手架 - V2EX 一个对比 JavaORM 框架的小仓库 - V2EX 想问一个关于 IO 流的细节 - V2EX 关于我在腾讯云 windows 服务器起了一个后端服务,但是服务器本地都请求不到的问题 11 - V2EX 分享一个 idea 的无响应 bug,如果你也遇到 - V2EX JNI 是否有向"简洁"演化的可能? - V2EX 多实例 springboot 微服务重启时 Counter 类型指标重置问题 - V2EX 讨论个问题:该不该重写 equal 和 hashcode - V2EX 求助 泛型转换碰到一个很奇怪的问题 Object 放 Redis 自动变成 JSONObject 了 - V2EX Java Agent 该怎么快速学习?有教程文档推一下吗? - V2EX 能不能别用那烦人的 MyBatis-Plus 了! - V2EX 作为 Java boy 你们业余时间会学点什么? - V2EX 各位 v 友们!有无无敌好用的剪辑软件求推荐! - V2EX 如何从反射的 Field/Method 动态构造 mybatis 的 SFunction? - V2EX Java 得冗余与啰嗦是不是对 AI 不友好 - V2EX 问一个日志不打印栈信息的问题 - V2EX 为何 RestTemplate 无法定制请求 - V2EX 日经吐槽:现在的 Java 语言真的有点令人恶心 - V2EX 新手 javaer 咨询几个问题 - V2EX 自学 Java 看不懂报错信息和代码,有什么推荐 ai 拿来自学的吗? - V2EX 用 netty 编写代理服务器,切换出口 IP,不能及时生效 - V2EX mysql 慢日志分析排查小工具 1.0.0 - V2EX Preferences.userNodeForPackage(Object.class)存储位置在哪里? - V2EX vscode 中 augment code 怎么使用 mcp - V2EX mysql 慢日志分析排查小工具 - V2EX Java 的一次编译到处运行在目前还有优势吗 - V2EX 现在学 Java 算 49 年入国军吗 - V2EX 推广一下自己刚撸的 IDEA 插件—Bean Copy 助手 - V2EX 几千万的数据量,层级权限下的列表展示页查询应该怎么设计? - V2EX 大家生产环境会一直开着 JFR 吗 - V2EX 有没有新版 Java 的佬(jdk25 和 21 这种), 上手还是走官方文档吗 - V2EX Java 程序员面经怎么准备 - V2EX
DoytoQuery vs SpringDataJPA - V2EX
f0rb · 2026-03-05 · via Java

这是一个创建于 101 天前的主题,其中的信息可能已经有所发展或是发生改变。

SpringDataJPA 支持通过 findBy 方法构建查询语句,然而 findBy 方法构建的查询条件是固定的,不支持忽略值为 null 的参数对应的查询条件,这导致我们需要为每一组参数组合定义一个 findBy 方法。例如:

findByAuthor
findByAuthorAndPublishedYearGreaterThan
findByAuthorAndPublishedYearLessThan
findByAuthorAndPublishedYearGreaterThanAndPublishedYearLessThan

当条件变多时,方法名会变长,参数也会变多,并触发“长参数”坏味道。解决这一问题的重构方法是“引入参数对象”,即把所有的参数定义在一个对象里。同时,我们把 findBy 的方法名中对应查询条件的部分作为这个对象的字段名称,我们便能为每个字段构建一个查询条件,并且根据对象的赋值情况,动态地组合非空字段对应的查询条件组合为查询子句。

public class BookQuery {
    String author;
    Integer publishedYearGreaterThan;
    Integer publishedYearLessThan;
    //...
}

基于此对象,我们可以把所有的 findBy 方法合并为一个泛型方法,从而简化查询接口的设计。

public class CrudRepository<E, I, Q> {
    List<E> findBy(Q query);
    //...
}

提出查询对象这一概念,并利用它来解决动态查询问题,正是 DoytoQuery 的核心功能。

beginor

1

beginor      3 月 5 日

建议可以参考一下 NHibernate 或者 EntityFramework 的 Linq 查询的实现,C#这边 Linq 已经快 20 年了,不知道为什么 Java 这边一直没有类似的东西出现,对 Java 不熟悉,不好评价。

f0rb

2

f0rb      3 月 5 日

@beginor Linq 这种需要编译期支持的就算了吧,Linq 真这么好咋没有其他任何编程语言跟进呢?

beginor

5

beginor      3 月 6 日 via Android

@f0rb 那 jpa 的这些方法是不是也依赖编译器呢?

beginor

6

beginor      3 月 6 日 via Android

@beginor linq 其实不依赖编译器编,因为 linq 表达式树不需要编译,是动态解释表达式树,转换为对应的 SQL 语句,依赖的是类型

f0rb

7

f0rb      3 月 7 日

@beginor

```c#
var query = from s in dbContext.Students
where s.Age >= 18
select s;
```
你说的是这种么?有第 2 个把 SQL 里的关键字直接拿来当编程语言的关键字的么?这种放其他语言直接编译出错。

JPA 的这些方法就只是普通的接口方法,解析方法名称用的是反射技术,不是编译器技术。

beginor

8

beginor      3 月 7 日

@f0rb 这种写法实际上会被转译成 lambda 表达式树,在实际开发中,往往大家更喜欢这么写:

```c#
var query = dbContext.Students.Where(s => s.Age >= 18);
var data = query.ToList();
```

甚至还可以动态拼接:

```c#
var age = //
var query = dbContext.Students;
if (age > 0) {
query = query.Where(s => a.Age >= age);
}
var data = query.ToList()
```

再高级一点儿,还可以运行时根据需要生成表达式树,添加数据库特定的扩展函数。

这些表达式不会被编译, 编译器只做类型检查,运行时根据参数动态转换成对应的 sql 语句。

Java (Hibernate/QueryDSL)就支持类似这样的查询

```java
query.select(s).where(s.age.gt(18))
```

但是使用体验和 c#相比真的很差。

除了 C#,确实极少有主流通用编程语言会为了数据库查询而直接修改语言本身的编译器,把 from, where, select 变成一级关键字,但是正因为这样,C# 是这种“伪 SQL 体验”做得最极致的一个。

f0rb

9

f0rb      3 月 7 日

@beginor 所以 linq 还是需要`if`语句来构造动态查询。

麻烦您评论前先了解一下别人的方案和区别好吗?
引入查询对象后是不需要显示编写`if`语句来构造动态查询的。
查询对象里哪个字段有赋值就把哪个字段的查询条件添加到查询语句里。
这才是 DoytoQuery 和传统 ORM 的根本性区别。

beginor

10

beginor      3 月 7 日 via Android

这些是编程语言的特性,还有逻辑算符,开发者已经掌握,只要做好映射,就可以直接使用。

如果一个 ORM 需要再学习并记住 le lt ge 等晦涩的方言表才能生成 SQL ,推广起来只会更难。

f0rb

12

f0rb      3 月 8 日

@freefcw Specification 接口是先根据查询参数构建 criteria ,再根据 criteria 构建查询语句。如果把 Specification 用到的参数聚合到一个对象中,就是先根据这个对象构建 criteria ,再构建查询语句。然后我就发现构建的查询语句跟这个查询对象直接相关,没必要依赖 criteria 多绕一圈。

https://github.com/f0rb/java-orm-comparison 这个仓库有跟 Specification 的写法做对比的,用 Specification 还是需要写大量 if 语句。用 DoytoQuery 则能根据查询对象自动构建动态查询语句,一行方法都不用写。

beginor

14

beginor      3 月 8 日 via Android

如果能再进一步,将 le lt ge 这些改为使用语开发内置的 '>=' '>' '<=' 逻辑算符来生成对应的查询语句(也就是构建并解析λ表达式树),不仅学习起来更加容易,使用上也更加流畅,对于现有的 Java ORM 来说,才是实质的进步,否则大家还是会倾向选择大众化的 MyBatis 或者 JPA 。

f0rb

15

f0rb      3 月 8 日

@beginor 有一点我想你没有理解清楚,就是引入查询对象后就可以实现查询语句的自动化构建。比如下面这个类,你看眼字段名就知道每个字段对应的查询条件是什么,完全不再需要去编写方法,用'>=' '>' '<=' 这些逻辑运算符去构建查询语句。这也是为什么需要把逻辑运算符转换成谓词后缀的原因。

public class BookQuery
{
public string Author { get; set; } // author = ?
public int PublishedYearGt { get; set; } // published_year > ?
public int PublishedYearLt { get; set; } // published_year < ?
}

你在 C#里把这个对象转换成 WHERE 语句恐怕连 300 行代码都用不了。

beginor

16

beginor      3 月 8 日

就个人来说,如果要先记住 Gt Lt 这些方言表,还不如用 mybatis 写 xml+sql 简单吧;

强依赖属性名称+谓词查询不是人人都能接受, 万一属性名称拼或谓词错了一个字母呢?

到 C#这边来说,也就是这几行代码,而且编译器会做类型检查,提前发现并排除不必要的错误:

```c#
var query = context.Books;

if (author != null) {
query = query.Where(book => book.Author == params.Author);
}
if (startYear > 0) {
query = query.Where(book => book.PublishedYear > startYear;
}
if (endYear > 0) {
query = query.Where(book => book.PublishedYear < endYear);
}

var books = query.ToList();
```

f0rb

17

f0rb      3 月 8 日

@beginor 所以你有没有想过我这里为什么会拿 SpringDataJpa 的 findBy 方法作为切入点呢?
1. 这种后缀就十几个,2. 后缀可以通过插件做提示和检查。
这些都是 SpringData 已经实现的,我在这个基础上进一步简化了动态查询条件的组合功能,这个很难理解吗?

mybatis 的 xml 里用 if 拼 SQL 会比定义几个字段更简单吗?那为什么都去用 mybatis-plus 了?

还有你这段 C#代码,你没发现用我前面写的 BookQuery 类可以生成一样涵义的代码吗?

你还是理解不了我说的自动化构建动态查询是什么意思吗?
引入查询对象后,不管是用反射还是代码生成,都是完全可以避免编写和维护这种包含大量 if 语句的代码的。