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,我看到的问题是:

  1. MachineGroup 正在引用一组版本,每个版本引用一组 MachineGroup
  2. 版本相同 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;
}