首页 > 解决方案 > HIbernate - 尝试获取数据时出现“无法初始化代理 - 无会话”错误

问题描述

我正在使用 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 和版本,我看到的问题是:

  1. MachineGroup 引用一组版本,每个版本引用一组 MachineGroup
  2. 版本类相同

看起来如何创建表是一个循环问题。我尝试使用 @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;

    }

标签: javasqlhibernateentity-relationship

解决方案


感谢@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;
}

推荐阅读