【发布时间】:2026-01-09 13:25:01
【问题描述】:
我正在使用 Spring Boot 和 MySql 休眠,我正在尝试找出处理错误的最佳方法
nested exception is com.fasterxml.jackson.databind.JsonMappingException: failed to lazily initialize a collection of role: "some class field" could not initialize proxy - no Session".
我看到了几个解决方案,但我无法让它们发挥作用,而且我不明白实施它们的后果。
我有以下实体:
@Entity
@Table(name="machine_groups_to_versions")
@Getter
@Setter
//@JsonIgnoreProperties(value= {"machineGroup", "version"})
public class MachineGroupToVersion {
@Id
@GeneratedValue(strategy= GenerationType.AUTO, generator = "machine_groups_to_versions_seq")
@SequenceGenerator(name = "machine_groups_to_versions_seq", allocationSize = 1)
@Column(name = "id")
private long id;
@ManyToOne
@JoinColumn(name = "machine_group_id", nullable = false)
private MachineGroup machineGroup;
@ManyToOne
@JoinColumn(name = "version_id", nullable = false)
private Version version;
@Column(name = "state")
private String state;
@Column(name = "tested_time")
private Date testedTime;
@Column(name = "creation_time")
private Date creationTime;
}
@Entity
@Table(name="versions")
@Getter
@Setter
public class Version {
@Id
@GeneratedValue(strategy = GenerationType.AUTO, generator = "versions_seq")
@SequenceGenerator(name = "versions_seq", allocationSize = 1)
@Column(name = "id")
private long id;
@Column(name = "name")
private String name;
@Column(name = "creation_time")
private Date creationTime;
@Column(name = "exe_file")
@Lob
private Blob exeFile;
@ManyToMany(mappedBy = "versions", cascade = CascadeType.MERGE)
private Set<MachineGroup> machineGroups = new HashSet<>();
}
@Entity
@Table(name="machine_groups")
@Getter
@Setter
@AllArgsConstructor(access = AccessLevel.PUBLIC)
@NoArgsConstructor
public class MachineGroup {
@Id
@GeneratedValue(strategy= GenerationType.AUTO, generator = "machine_groups_seq")
@SequenceGenerator(name = "machine_groups_seq", allocationSize = 1, initialValue = 2)
@Column(name = "id")
private long id;
@Column(name = "name")
private String name;
@Column(name = "creation_time")
private Date creationTime;
@Column(name = "is_official")
private boolean official;
@OneToOne(cascade = CascadeType.ALL)
@JoinColumn(name = "machine_properties_id", nullable = false)
private ContinuousIntegrationProperties defaultContinuousIntegrationProperties;
@ManyToMany(fetch = FetchType.EAGER)
@JoinTable(name = "machine_groups_to_users",
joinColumns = @JoinColumn(name = "machine_group_id"),
inverseJoinColumns = @JoinColumn(name = "user_id"))
private Set<User> users = new HashSet<>();
@ManyToMany(cascade = CascadeType.MERGE)
@JoinTable(name = "machine_groups_to_versions",
joinColumns = @JoinColumn(name = "machine_group_id"),
inverseJoinColumns = @JoinColumn(name = "version_id"))
private Set<Version> versions = new HashSet<>();
}
我的控制器:
@GetMapping("/getByMachineGroupName/{machineGroupName}")
public ResponseEntity<List<MachineGroupToVersionDTO>> getAllVersions(@PathVariable String machineGroupName) {
logger.info("Incoming GetMachineGroupToVersionReport Request. Machine Group Name: {}", machineGroupName);
List<MachineGroupToVersionDTO> omgtv = machineGroupToVersionService.getByMachineGroupName(machineGroupName).stream()
.map(this::convertToDto).collect(Collectors.toList());
return new ResponseEntity<>(omgtv, HttpStatus.OK);
}
当我调试时,我可以看到我的 omgtv 有我需要的所有数据,但由于某种原因它无法返回。
正如您在我的 MachineGroupToVersion 类中看到的,我提取 MachineGroup 和版本,我看到的问题是:
- MachineGroup 引用了一组版本,每个版本都引用了一组 MachineGroup
- Version 类也是如此
表的创建方式看起来像一个循环问题。 我尝试使用 @JsonIgnoreProperties 注释,但它只是将其从响应中删除,这不是预期的结果。
我看到了显示错误所在的跟踪,但我该如何解决这个问题?
through reference chain: java.util.ArrayList[0]->entities.machinegrouptoversion.MachineGroupToVersionDTO[\"machineGroup\"]->entities.machinegroup.MachineGroup[\"users\"]->org.hibernate.collection.internal.PersistentSet[0]->entities.user.User[\"machineGroups\"]
除非我专门调用 get 函数,否则我不想让一切都变得急切。
如何在不更改类和数据库结构的情况下解决此问题?
更新:
服务
- 列表项
@Transactional(transactionManager = "primaryTransactionManager", propagation= Propagation.REQUIRED, readOnly=true, noRollbackFor=Exception.class)
public List<MachineGroupToVersionDTO> getByMachineGroupName(String mgName) {
List<MachineGroupToVersionDTO> mgtvl = new ArrayList<>();
Optional<MachineGroup> mg = machineGroupService.getByName(mgName);
if(mg.isPresent())
mgtvl = machineGroupToVersionRepository.findByMachineGroup(mg.get()).stream()
.map(this::convertToDto).collect(Collectors.toList());
return mgtvl;
}
private MachineGroupToVersionDTO convertToDto(MachineGroupToVersion mgtv) {
MachineGroupToVersionDTO machineGroupToVersionDTO = new MachineGroupToVersionDTO();
machineGroupToVersionDTO.setMachineGroup(mgtv.getMachineGroup());
machineGroupToVersionDTO.setVersion(mgtv.getVersion());
machineGroupToVersionDTO.setCreationTime(mgtv.getCreationTime());
machineGroupToVersionDTO.setState(mgtv.getState());
machineGroupToVersionDTO.setTestedTime(mgtv.getTestedTime());
return machineGroupToVersionDTO;
}
【问题讨论】:
-
我猜您在
machineGroupToVersionService中有@Transactional,并且您转换为DTO 会尝试加载其他内容。要么急切地加载所有内容,要么将您的 DTO 转换转移到服务中。 -
我的服务中没有@Transcantional。将 DTO 转换移至服务是什么意思?在哪里创建 convertToDto 方法有什么不同?
-
另外,当我急切地加载所有内容时,有效负载非常非常大,我无法在客户端处理它......
-
如果你在那里有
@Transactional会有所不同。关键是您需要数据,因此您需要急切地获取它,或者在 Hibernate 会话仍处于活动状态时进行 DTO 转换,以便仍然可以加载它。尝试将@Transactional添加到服务中并将 dto 转换移到那里,即使您不希望这样做 - 只是为了检查它是否有效。 -
您没有完全映射到 DTO -
machineGroupToVersionDTO.setMachineGroup(mgtv.getMachineGroup());。你需要映射整个结构,你在这里传递一个实体。
标签: java sql hibernate entity-relationship