HIbernate - "could not initialize proxy - no Session" 尝试获取数据时出错
HIbernate - "could not initialize proxy - no Session" error when trying to fetch data
我正在使用 spring 引导和休眠 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 拥有我需要的所有数据,但由于某种原因它无法 return 它。
如您在我的 MachineGroupToVersion class 中所见,我提取了 MachineGroup 和 Version,我看到的问题是:
- MachineGroup 正在引用一组版本,每个版本引用一组 MachineGroup
- 版本相同 class
看起来像是一个与表的创建方式有关的循环问题。
我尝试使用 @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 函数。
如何在不改变我的 classes 和数据库的结构的情况下解决这个问题?
更新:
服务
- 列表项
@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;
}
感谢@Shadov,我得以找到问题所在。就我而言,问题是我在创建 DTO 时犯的错误。
我错误地创建了包含字段的 DTO,这些字段是实体而不是其他 DTO。一旦我将它们从实体更改为 DTO,我就能够得到我需要的响应。
由此改变:
public class MachineGroupToVersionDTO {
private MachineGroup machineGroup;
private Version version;
private String state;
private Date testedTime;
private Date creationTime;
}
为此:
public class MachineGroupToVersionDTO {
private MachineGroupSimpleDTO machineGroup;
private VersionDTO version;
private String state;
private Date testedTime;
private Date creationTime;
}
我正在使用 spring 引导和休眠 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 拥有我需要的所有数据,但由于某种原因它无法 return 它。
如您在我的 MachineGroupToVersion class 中所见,我提取了 MachineGroup 和 Version,我看到的问题是:
- MachineGroup 正在引用一组版本,每个版本引用一组 MachineGroup
- 版本相同 class
看起来像是一个与表的创建方式有关的循环问题。 我尝试使用 @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 函数。
如何在不改变我的 classes 和数据库的结构的情况下解决这个问题?
更新:
服务
- 列表项
@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;
}
感谢@Shadov,我得以找到问题所在。就我而言,问题是我在创建 DTO 时犯的错误。
我错误地创建了包含字段的 DTO,这些字段是实体而不是其他 DTO。一旦我将它们从实体更改为 DTO,我就能够得到我需要的响应。
由此改变:
public class MachineGroupToVersionDTO {
private MachineGroup machineGroup;
private Version version;
private String state;
private Date testedTime;
private Date creationTime;
}
为此:
public class MachineGroupToVersionDTO {
private MachineGroupSimpleDTO machineGroup;
private VersionDTO version;
private String state;
private Date testedTime;
private Date creationTime;
}