Spring 数据 JDBC 一对多关系导致大量日志警告

Spring Data JDBC one-to-many relation causes lots of log warnings

摘要:Spring 数据发出警告,因为它 SELECT 在同一列中两次。警告是:

(...) WARN o.s.d.j.core.convert.ResultSetAccessor   : ResultSet contains id multiple times

这是 spring-boot-starter-data-jdbc 通过 Spring Boot 2.5.5 (documentation)。我正在处理一个非常基本的一对多关系:

为简洁起见,我已尽可能减少实体 类,同时保留警告:

Outlet.java

(...)
@Table("outlet")
public class Outlet {
    @Id
    private String outletId;
    @MappedCollection(idColumn = "outlet_id", keyColumn = "id")
    private Map<String, OfferedService> offeredServices;
    (...)
}

OfferedService.java

(...)
@Table("offered_service")
public class OfferedService {
    @Id
    private String id;
    private String outletId;
    (...)    
}

存储库也是最基本的...

OutletRepository.java

(...)
public interface OutletRepository extends CrudRepository<Outlet, String> {}

...在我的应用程序代码中,我只是在此存储库上执行 findAll

(...)
outletRepo.findAll();
(...)

这会导致查询选择同一列两次,随后会出现来自 Spring 数据 ResultSetAccessor:

的警告
DEBUG o.s.jdbc.core.JdbcTemplate               : Executing prepared SQL statement [
    SELECT "outlet"."outlet_id" AS "outlet_id" FROM "outlet"]
DEBUG o.s.jdbc.core.JdbcTemplate               : Executing prepared SQL query
DEBUG o.s.jdbc.core.JdbcTemplate               : Executing prepared SQL statement [
    SELECT "offered_service"."id" AS "id", 
        "offered_service"."outlet_id" AS "outlet_id", 
        "offered_service"."id" AS "id"
    FROM "offered_service"
    WHERE "offered_service"."outlet_id" = ?]
TRACE o.s.jdbc.core.StatementCreatorUtils      : Setting SQL statement parameter value: 
    column index 1, parameter value [xyz012], value class [java.lang.String], SQL type 12
WARN  o.s.d.j.core.convert.ResultSetAccessor   : ResultSet contains id multiple times
WARN  o.s.d.j.core.convert.ResultSetAccessor   : ResultSet contains id multiple times
(...repeated many times...)

我在这里做错了什么?另外,对于 findAll,这不应该首先是 JOIN 吗?

您有两件事映射到列 offered_service.outlet_id: 从OutletOfferedService的一对多映射和属性OfferedService.outletId.

如果这些应该不同,您可以使用注释来更改它们映射到的列,但我假设您是故意这样做的,以便在 OfferedService 中提供 outletId实体。

虽然这可行,但它有点像 hack,可能会在未来的版本中崩溃。

推荐的做法是使用 @Transient 使 outletId 成为瞬态,并在添加 OfferedService 时使用纯 java 代码设置其值Outlet.

有一篇关于此的博客文章:https://spring.io/blog/2021/09/22/spring-data-jdbc-how-do-i-make-bidirectional-relationships

似乎还有另一个问题,其中 Spring 数据 JDBC 执行 select OfferedService.id 两次。我不确定为什么会这样。对我来说看起来像个错误。但是您可能可以完全删除 id,因为映射键和 outlet_id 应该形成一个完美的主键。