跳到主要内容

6.6 常见问题

Q:使用 DLZ-DB 还需要写 Mapper 或 DAO 吗?

常规 CRUD 不需要。业务代码可以直接使用 DB.pojoDB.tableDB.jdbcDB.sql。是否保留 Repository/Service 由项目的业务分层决定,而不是由 DLZ-DB 强制。

Q:如何处理复杂的 JOIN 查询?

使用原生 SQL 或预设 SQL:

String sql = "SELECT u.*, d.name AS dept_name "
+ "FROM user u "
+ "LEFT JOIN department d ON u.dept_id = d.id "
+ "WHERE u.status = ?";
List<ResultMap> list = DB.jdbc.selectWrapper(sql, 1).queryList();

Q:如何实现乐观锁?

int updated = DB.pojo.updateWrapper(User.class)
.set(User::getName, newName)
.set(User::getVersion, user.getVersion() + 1)
.eq(User::getId, user.getId())
.eq(User::getVersion, user.getVersion())
.execute();

if (updated == 0) {
throw new OptimisticLockException("数据已被修改");
}

DLZ-DB 当前没有自动版本字段插件。更新语句必须同时包含主键和旧版本条件,并检查影响行数。

Q:如何调试 SQL?

开启 dlz.db.log.show-run-sql 后,日志会显示展开参数的 SQL 和执行耗时。开启 show-caller 会向 MDC 注入调用方信息,是否显示取决于日志 pattern。展开 SQL 用于排查,复制到数据库工具前仍应检查敏感值、方言和转义结果。

Q:性能和 MyBatis 比怎么样?

DLZ-DB 底层基于 JDBC,但端到端性能还取决于 SQL、结果映射、日志、连接池和数据库。没有统一的性能结论;请在实际数据集上用相同 SQL 做 benchmark。

Q:为什么没有业务条件的更新或删除没有被拒绝?

空 WHERE 会被构建为 WHERE false,但逻辑删除自动增加的 deleted = 0 已经构成 WHERE。因此没有业务条件的 UPDATE/DELETE 仍可能影响全部未删除数据。每个写 Wrapper 都必须显式添加主键或业务范围条件,详见 写操作安全限制

Q:如何查询已逻辑删除的数据?

接收 DbOption... 的直接查询可以传 SelectOption.INCLUDE_DELETED,例如 DB.pojo.selectById(User.class, id, SelectOption.INCLUDE_DELETED)。Pojo 查询 Wrapper 当前没有对称的稳定便捷方法。

Q:Solon 下怎么用?

参见 Solon 快速开始Solon 完整集成。除 DLZ-DB 配置外,容器中还必须有可用的 DataSource Bean。

Q:能和 MyBatis 共存吗?

依赖层面可以同时引入,DLZ-DB 不依赖 MyBatis 体系。如果两者需要共享数据源或 Spring 事务,应针对实际数据源、事务管理器和连接获取路径做集成测试,不应仅根据“能启动”就推断事务语义一致。

渐进迁移步骤见 从 MyBatis 迁移

Q:为什么 IDE 能补全到 internal 类型?

8.0 的部分 Wrapper 继承关系,以及 Sort/Page 模型继承链,仍暴露实现层接口。可见不等于稳定;业务代码不得导入 com.dlz.db.internal.*,只使用参考手册明确展示的 Wrapper 和模型方法。详见 API、SPI 与实现边界

Q:分页 count 对所有 SQL 都可靠吗?

不可靠。Pojo/Table Wrapper 的单表分页是默认路径;原生 JDBC 的自动 count 是轻量字符串改写,复杂 GROUP BYDISTINCTUNION 和子查询应提供经过验证的查询与 count 方案。

Q:配置修改后为什么没有生效?

只依赖 core 手动启动时,DB.config 在调用它自己的 init() 后不可变。Spring Boot/Solon 不读取这套待手动初始化的配置状态,应通过容器 DataSourcedlz.db.* 和应用启动生命周期完成初始化;预设 SQL 也在启动阶段载入。不要在业务请求中修改全局配置,配置文件发生变化后通常需要重启并重新初始化应用。