You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Spring Boot问题:数据库存在参与者但日程列表不显示

问题:Spring Boot多对多关联中Schedule的参与者数据无法加载

问题描述

开发Spring Boot项目时,Schedule实体与User实体配置多对多关联,参与者已成功存入数据库的中间表,但查询日程数据时,参与者集合始终为空。具体表现:

  • 直接在数据库执行Spring生成的查询语句能查到参与者数据
  • HTML页面仅参与者信息不显示,其他日程字段正常
  • Service和Controller中打印日志显示参与者集合为空
  • 尝试自定义查询、手动设置关联均无效

代码片段

Schedule.java

@Entity
@Table(name="schedule")
@Data
@NoArgsConstructor
@AllArgsConstructor
public class Schedule {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long scheduleId;

    @Column(name = "date", nullable = false)
    private Date date;

    @Column(name = "start_time", nullable = false)
    private LocalTime startTime;

    @Column(name = "end_time", nullable = false)
    private LocalTime endTime;

    @Column(name = "trainer_id", nullable = false)
    private Long trainerId;

    @ManyToMany(fetch = FetchType.EAGER)
    private Set<User> participants;
}

User.java

@Entity
@Table(name="users")
@Data
@NoArgsConstructor
@AllArgsConstructor
public class User {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long userId;

    @NotBlank(message = "Username is required")
    @Size(min = 3, max = 20, message = "Username must be between 3 and 20 characters")
    @Column(name = "username", unique = true, nullable = false)
    private String username;

    @NotBlank(message = "Email is required")
    @Pattern(regexp = "(?i)^[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\\.[A-Z]{2,6}$", message = "Email must be valid")
    @Column(name = "email", unique = true, nullable = false)
    private String email;

    @NotBlank(message = "Password is required")
    @Size(min = 8, message = "Password must be at least 8 characters")
    @Pattern(regexp = "^[^\\s]*$", message = "Password must not contain spaces")
    @Column(name = "password", nullable = false)
    private String password;

    @ElementCollection(fetch = FetchType.EAGER)
    @CollectionTable(name = "roles", joinColumns = @JoinColumn(name = "userId"))
    @Column(name = "role")
    private Set<String> roles;

    @ManyToMany(mappedBy = "participants")
    private Set<Schedule> schedules;
}

其余Service、Controller、HTML代码见原提问。

解决方案

1. 补全多对多关联的中间表配置

问题核心是Schedule实体的@ManyToMany注解未指定中间表信息,JPA默认生成的中间表名/字段名可能与实际数据库中的不一致,导致无法加载关联数据。

修改Schedule类中的participants字段注解,明确指定中间表名称及关联字段(替换为数据库中实际的表名和字段名):

@ManyToMany(fetch = FetchType.EAGER)
@JoinTable(
    name = "schedule_participants", // 你的中间表名称
    joinColumns = @JoinColumn(name = "schedule_id"), // 中间表中关联Schedule的字段名
    inverseJoinColumns = @JoinColumn(name = "user_id") // 中间表中关联User的字段名
)
private Set<User> participants;

2. 同步双向关联(可选但推荐)

虽然Schedule是多对多关联的主控方(owning side),仅保存Schedule即可持久化关联,但为了保证双向关联的一致性,建议在添加参与者时同步更新User的schedules集合:

修改ScheduleService中的scheduleSession方法:

public void scheduleSession(Long trainerId, List<Long> userIds, Date date, LocalTime startTime, LocalTime endTime) {
    // ... 原有代码 ...
    
    schedule.setParticipants(participants);
    Schedule savedSchedule = scheduleRepository.save(schedule);

    // 同步User的schedules集合
    for (User user : participants) {
        user.getSchedules().add(savedSchedule);
        userRepository.save(user);
    }

    // ... 原有日志代码 ...
}

3. 验证SQL查询(调试用)

在application.properties中开启SQL日志,确认查询Schedule时是否正确关联中间表:

spring.jpa.show-sql=true
spring.jpa.properties.hibernate.format_sql=true

查看日志输出的SQL,如果没有包含对中间表的JOIN操作,说明中间表配置仍有问题,需核对表名和字段名是否与数据库完全一致。

4. 检查实体类的equals/hashCode

@Data注解自动生成的equals/hashCode基于所有字段,对于关联对象来说,确保User类的equals/hashCode仅依赖主键userId(避免循环引用或集合识别问题)。如果需要,可以手动重写:

@Override
public boolean equals(Object o) {
    if (this == o) return true;
    if (o == null || getClass() != o.getClass()) return false;
    User user = (User) o;
    return Objects.equals(userId, user.userId);
}

@Override
public int hashCode() {
    return Objects.hash(userId);
}

验证

修改后重启项目,调用查询接口,查看日志是否能打印参与者信息,同时检查HTML页面是否正常显示参与者列表。

内容的提问来源于stack exchange,提问作者Nick Richardson

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.16 11:22:32