火柴人武林大会
156.74M · 2026-02-04
前几天写业务接口,有个复杂的查询,当我熟练地打开一个几百行的 XML,准备第N次敲下 <where> 和 <if test="..."> 时,突然愣神了。
我一个臭写 Java 的,怎么半数时间在写 XML?
为了一个查询,我要在 Java 接口、XML 映射文件、实体类之间反复切换。要是字段名一不小心写错了,还得等到代码运行的时候,才能再一不小心地抛出个 NullPointerException 。
其实这种割裂感已经存在许久了。
于是,利用几个熬夜的周末,我搞出了 LumenORM。
诚然,它是一个美丽小废物——没生态、没大厂背书、甚至可能还有一堆 Bug。但它做了一件我一直想做的事:把 SQL 交还给 Java,让拓展的 XML 文件彻底离开了视线。
Love SQL, hate XML? A fresh choice for Java developers.
毕竟我们总是要写很多复杂的查询,离开SQL总是不行的。
一如 Mybatis 在国内的火爆,不得不承认,只有 SQL-First 才更适合国内业务的体质。
直接看个例子,一目了然:
public interface UserRepository extends SqlTemplate {
@SqlTemplate("""
SELECT id, name, email FROM users
WHERE deleted = false
@if(#{name}) {
AND name LIKE #{like(#{name})}
}
@orderBy(#{sortBy}) {
ORDER BY #{sortBy} #{sortDir}
}
@page(#{page}, #{size}) {
LIMIT #{offset}, #{size}
}
""")
List<User> search(UserSearchCriteria criteria);
}
一套逻辑,一个文件,一眼看穿。
条件成立,就拼接SQL,条件不成立就不处理。
看着好像还行。
但是我有时候就是不想写SQL,比方说就一些很简单的增删改查,怎么办?
那 LumenORM 也提供了类型安全的 DSL。
var t = dsl.table(User.class).as("u");
var stmt = dsl.select(t.cols(User::getId, User::getName))
.from(t)
.where(w -> w.and(t.col(User::getStatus).eq("ACTIVE")))
.orderBy(o -> o.desc(t.col(User::getCreatedAt).expr()))
.build();
在这里,IDE 就充分发挥了优势 。也不用怕字段写错了,直接在编译器就能预警问题,再也不需要等到运行时才去排查 SQL 语法错误。
MyBatis 让你自己处理 NOW() 或 UUID(),在 LumenORM 里,我内置了一些常用的语法糖:
#{now()} :自动填充当前时间。#{uuid()} :生成唯一标识。#{like(val)} :自动帮你处理 %val%,别再手动拼字符串了。@for 循环:写 IN 子句不再需要背那复杂的 collection/item/separator 属性。当然还远不止这些。
为了更快的性能, LumenORM 极少使用反射,而是采用 APT 编译器生成技术,并且也减少了黑盒机制,确保所有的代码都是公开透明。
为了避免 @SqlTemplate 里面的SQL有格式错误, LumenORM 专门做了编译器的语法检测,如果有语法不过关,能够在编译阶段就暴露出问题。
这类小细节还有很多,诸君可以翻看源码找找惊喜。
正如文章开头所说,这只是一个美丽的小废物。
我不打算吹嘘它能取代谁。
作为一个业余的作品,它的短板非常明显:
@SqlTemplate 提供高亮(毕竟它只是个字符串)。LumenORM 并不完美,它甚至可能带给你新的折磨——但至少,那是属于 Java 里的折磨,而不是 XML 的。
变成最纯粹的Javaer。
如果你也像我一样不喜欢XML,欢迎来点个 Star,或者提交一个优雅的 PR。