一个不到 7000 行代码的 Java 数据库框架,让你写 SQL 像写本地代码一样直接。
List<User> users = DB.Pojo.select(User.class)
.eq(User::getStatus, 1)
.like(User::getName, "张")
.orderByDesc(User::getCreateTime)
.queryBeanList();没有 Mapper 接口,没有 Service 层,没有 XML。
当前版本 v7.0.0(开源初始版 v6.6.4)。
这个项目不是从零开始的。它大约在 2009 年开始积累,2014 年左右成型,作为公司内部的数据库操作工具包投入使用。此后十年间,累计被数十个内部项目采用,适配过各种老旧系统、各种开源框架组合、各种奇奇怪怪的版本混搭。
2024 年,我们决定将它开源。为此做了大量重构和删减——剥离内部依赖、清理历史包袱、提炼通用能力,最终发布了第一个公开版本 6.6.4。
所以版本号不是从 1.0 开始的——因为你看到的是一个已经跑了十几年的工具,被数十个项目验证过,而不是一个刚起步的新项目。
如果你写过一段时间 Java,大概率经历过这些:
- 为了一次简单的 CRUD,创建 6 个文件、200 行代码。
- 线上日志一条 SQL,全局搜半小时找不到是谁执行的。
@DS("slave")写在注解里,新租户动态接入?对不起,字符串硬编码。- MyBatis 出异常,栈里 15 层代理,看不出错在哪一行业务代码。
- 查询返回一个 JSON 字段,还得自己
JSON.parseObject(...)一层层剥。
DLZ-DB 想解决的不是"没有框架",而是**"框架长在了用户不想要它长的地方"**。
caller:(UserController.java:42) getList 15ms sql:SELECT * FROM user WHERE id = 1
↑ ↑ ↑
IDE 点这里直接跳转 真实耗时 参数已填充,复制即可执行
MyBatis 日志告诉你"有一条 SQL 跑了",DLZ-DB 告诉你**"是你的 UserController 第 42 行跑的"**。生产排查时,这一条就值回票价。
@DS("slave") 在编译期就把数据源 key 写死了。想按租户、按 Header、按灰度规则路由?SpEL 补丁、手动 push/pop、AOP 顺序……每一步都在和框架较劲。
DLZ-DB 把两端都做成字符串:
// 运行时注册一个新数据源
DB.Dynamic.setDataSource(prop);
// 运行时用任意逻辑决定走哪个库
String dsName = routeByTenant(tenantId);
User user = DB.Dynamic.use(dsName, () ->
DB.Pojo.select(User.class).eq(User::getId, id).queryBean()
);SaaS 多租户、动态数据源管理、ETL 工具、灰度迁移——这些场景里注解派要绕一大圈,这里两行解决。
这不是"功能少",是**"不做你不需要的事"**:
- 不做 Mapper 接口和 XML 双向映射 → 省掉解析引擎。
- 不做 SqlSession / Executor 分层 → 调用栈直通 JDBC。
- 不做一二级缓存 → 交给 Redis / Caffeine,各司其职。
你因此得到的实际好处:
- 可通读:整个框架没有黑盒,出 bug 能自己跟进源码。
- 可定制:想改一个行为?fork 下来一眼能看到改哪里。
- 异常栈短:查询异常直接告诉你 SQL 在哪,不需要穿越 10 层代理。
- 部署轻:jar 体积小、启动快、常驻内存低,适合微服务和工具类项目。
运行时单次查询性能与 MyBatis 相近——数据库才是瓶颈,框架层差距可以忽略。我们不在这个维度卷。
ResultMap result = DB.Table.select("user").eq("id", 1).queryOne();
result.getInt("age", 0);
result.getStr("profile.address.city", "未知"); // profile 是 JSON 字段
result.getList("orders", Order.class); // orders 是 JSON 数组ResultMap 继承自 JSONMap,a.b.c 路径取值是原生能力,不用自己 JSON.parseObject 再一层层 .get。
DLZ-DB 整个框架的审美是一致的:用显式的 lambda 和链式,对抗隐式的注解和代理。
// 条件判断:三参形式,不用写 if
.eq(name != null, "name", name)
// 嵌套逻辑:lambda 就地表达
.or(o -> o.like(User::getName, "关键词").like(User::getAddress, "关键词"))
// 数据源作用域:lambda 包起来
DB.Dynamic.use("other_db", () -> { ... });
// 空值自动忽略:SQL 里用方括号
[AND status = #{status}]代码里能看见的控制流,才是真正可靠的控制流。
DLZ-DB v7 采用多模块架构,可根据运行环境选择依赖:
| 模块 | 说明 | 适用场景 |
|---|---|---|
dlz-db-core |
核心模块,零 Spring 依赖 | 手动集成、非 Spring 项目 |
dlz-db-spring-boot-starter |
Spring Boot 自动配置 | Spring Boot 项目(推荐) |
dlz-db-solon-plugin |
Solon 插件 | Solon 项目 |
<dependency>
<groupId>top.dlzio</groupId>
<artifactId>dlz-db-spring-boot-starter</artifactId>
<version>7.0.0</version>
</dependency>spring:
datasource:
url: jdbc:mysql://localhost:3306/test
username: root
password: 123456
# DLZ-DB 配置(可选)
dlz:
db:
logic-delete-field: is_deleted
log:
show-run-sql: true
show-caller: true@Configuration
@EnableConfigurationProperties(SpringDlzDbProperties.class)
public class DlzDbConfigs extends SpringDlzDbConfig {}包路径:
com.dlz.db.spring.config.SpringDlzDbConfig、com.dlz.db.spring.config.SpringDlzDbProperties
@Data
public class User {
private Long id;
private String name;
private Integer age;
private Integer isDeleted; // 可选:存在即启用逻辑删除
private Date createTime;
}
@RestController
public class UserController {
@GetMapping("/user/{id}")
public User getUser(@PathVariable Long id) {
return DB.Pojo.select(User.class).eq(User::getId, id).queryBean();
}
}没了。 不需要 Mapper,不需要 Service,不需要 XML。
<dependency>
<groupId>top.dlzio</groupId>
<artifactId>dlz-db-solon-plugin</artifactId>
<version>7.0.0</version>
</dependency>dlz:
db:
logic-delete-field: is_deleted
log:
show-run-sql: true
show-caller: trueSolon 数据源配置(以 HikariCP 为例):
datasource:
default:
jdbcUrl: jdbc:mysql://localhost:3306/test
username: root
password: 123456
driverClassName: com.mysql.cj.jdbc.DriverSolon 下 API 完全一致,DB.Pojo/DB.Table/DB.Jdbc/DB.Sql 接口不变:
@Component
public class UserService {
public User getUser(Long id) {
return DB.Pojo.select(User.class).eq(User::getId, id).queryBean();
}
}Solon 事务使用 @Tran 注解:
@Tran
public void transfer(Long fromId, Long toId, BigDecimal amount) {
DB.Pojo.update(Account.class)
.setSql("balance = balance - #{amount}", Params.of("amount", amount))
.eq(Account::getId, fromId)
.execute();
DB.Pojo.update(Account.class)
.setSql("balance = balance + #{amount}", Params.of("amount", amount))
.eq(Account::getId, toId)
.execute();
}// 查询
User u = DB.Pojo.select(User.class).eq(User::getId, 1).queryBean();
List<User> list = DB.Pojo.select(User.class).eq(User::getStatus, 1).queryBeanList();
Page<User> page = DB.Pojo.select(User.class)
.setPage(Page.build(1, 10, Order.desc("create_time")))
.queryBeanPage();
// 插入
DB.Pojo.insert(user);
DB.Batch.insert(users, 100);
// 更新
DB.Pojo.update(user).eq(User::getId, id).execute();
DB.Pojo.update(User.class).set(User::getName, "新名字").eq(User::getId, id).execute();
// 删除(有 isDeleted 字段自动走逻辑删除)
DB.Pojo.delete(User.class).eq(User::getId, id).execute();
// 预设 SQL(xml / db 中定义,key 以 "key." 开头)
List<User> users = DB.Sql.select("key.user.find")
.addPara("status", 1)
.queryList(User.class);主操作入口(按 SQL 风格选一个)
├─ DB.Pojo ← 有 Bean 时首选,链式 + Lambda,类型安全
├─ DB.Table ← 动态表名场景,不需要 Bean
├─ DB.Jdbc ← 一行搞定的简单 SQL,? 占位符,秒迁 JdbcTemplate
└─ DB.Sql ← 复杂 / 动态 / 可复用 SQL,#{} 占位符 + 预设 SQL
正交能力(任何时候可叠加)
├─ DB.Batch ← 批量写入
└─ DB.Dynamic ← 数据源切换作用域
- 入口收敛到
DB.,决策树很浅。 - 条件方法统一
(condition, field, value)三参形式,特例少。 - 返回值有机械规则:带
Bean→ Bean,不带 → Map,带(Class)→ 指定类型。 - 整个使用规范可以压进 1000 token 以内塞给 AI(见 docs/第05章-AI辅助/5.1-AI速读.md)。
Q:复杂 SQL 怎么写?
// 原生 SQL
DB.Jdbc.select("复杂的SQL语句 where id=?", id).queryList();
// 预设 SQL
DB.Sql.select("key.复杂查询").addPara("x", 1).queryList();
// 条件构造器 + 自定义片段
DB.Pojo.select(User.class)
.eq(User::getStatus, 1)
.sql("EXISTS (SELECT 1 FROM vip WHERE user_id=t.id AND level>=#{lv})",
new JSONMap("lv", 3))
.queryBeanList();Q:如何调试 SQL?
打开 dlz.db.log.show-run-sql=true,日志会直接显示:
- 完整的可执行 SQL(参数已填充,可直接复制执行)
- 执行耗时
- 调用代码位置(IDE 中可点击跳转)
Q:性能如何?
底层直通 JDBC,无额外反射/代理损耗。与 MyBatis 运行时接近,不是我们的主要卖点——我们卖的是简单和可控,不是性能。
Q:能和现有 MyBatis / MP 项目共存吗?
可以。DLZ-DB 不依赖 MyBatis 体系,两者走各自的数据源和连接即可。迁移可以渐进——新模块用 DLZ-DB,老模块保持不动。
Q:v7 和 v6 的 API 兼容吗?
DB.Pojo/DB.Table/DB.Jdbc/DB.Sql 等核心 API 完全兼容。但 Maven 坐标、配置类包路径有变更,详见 6.2-v6升级到v7。
- 5.1 AI 速读(AI 代码生成规范)
- 5.1 AI Quick Reference (English)(English AI Quick Reference)
- 7.1 最佳实践
Apache License 2.0 © DLZ KIT