为什么 spring 引导应用程序的一对多关系中的子集合为空?

Why is the child collection is null in One-To-Many relationship of spring boot application?

我使用 MySQL、JPA、Web 依赖项创建了一个 spring 引导应用程序,并在 Spring 引导的 .properties 文件中手动配置我的数据库设置。编译通过,应用启动成功,添加一条记录正常。

但是,我使用方法 'findAll(Pageable pageable)' 我遇到了一个问题,那就是

Could not write JSON: failed to lazily initialize a collection of role,could not initialize proxy - no Session

一头雾水,开始debug代码,最后发现result的child collection为null,并且报错

"Exception occurred: com.sun.jdi.InvocationException occurred invoking method.."

我尝试了很多来修复我的代码,但没有用。 谁能帮帮我?

实体关系是简单的一对多: TeacherInfo实体和ClassInfo实体,教师管理多个类,就这么简单

这是我的应用程序的入口点:

@SpringBootApplication(exclude= {
        DataSourceAutoConfiguration.class,
        HibernateJpaAutoConfiguration.class,
        DataSourceAutoConfiguration.class
})
@EnableTransactionManagement
public class OrmTestApplication {

    public static void main(String[] args) {
        SpringApplication.run(OrmTestApplication.class, args);
    }
}

数据库属性设置在这里:

spring.datasource.primary.url=jdbc:mysql://localhost:3306/ormtest?useSSL=false
spring.datasource.primary.username=root
spring.datasource.primary.password=BlaNok2700
spring.datasource.primary.driver-class-name = com.mysql.jdbc.Driver

hibernate.hbm2ddl.auto = update
hibernate.show-sql = true

我的数据库配置java代码在这里:

Configuration
@EnableJpaRepositories(basePackages = "com.lanjian.ormtest.repositories", entityManagerFactoryRef = "primaryEntityManagerFactory", transactionManagerRef = "primaryTransactionManager")
public class PrimaryDbConfig {

@Autowired
private Environment env;

@Bean
@ConfigurationProperties(prefix="spring.datasource.primary")
public DataSourceProperties primaryDataSourceProperties() {
    return new DataSourceProperties();
}

@Bean
public DataSource primaryDataSource() {
    DataSourceProperties dbProperty = primaryDataSourceProperties();
    return DataSourceBuilder.create()
            .driverClassName(dbProperty.getDriverClassName())
            .url(dbProperty.getUrl())
            .username(dbProperty.getUsername())
            .password(dbProperty.getPassword())
            .build();
}

@Bean
public LocalContainerEntityManagerFactoryBean primaryEntityManagerFactory() {
    LocalContainerEntityManagerFactoryBean factory = new LocalContainerEntityManagerFactoryBean();
    factory.setDataSource(primaryDataSource());
    factory.setPackagesToScan("com.lanjian.ormtest.entities");
    factory.setJpaVendorAdapter(new HibernateJpaVendorAdapter());

    Properties jpaProperties = new Properties();
    jpaProperties.put("hibernate.hbm2ddl.auto", env.getProperty("hibernate.hbm2ddl.auto"));
    jpaProperties.put("hibernate.show-sql", env.getProperty("hibernate.show-sql"));
    factory.setJpaProperties(jpaProperties);
    return factory;
}

@Bean
public PlatformTransactionManager primaryTransactionManager() {
    EntityManagerFactory factory = primaryEntityManagerFactory().getObject();
    return new JpaTransactionManager(factory);
}

}

我的 REST 控制器方法在这里:

@Autowired
private TeacherRepository teacherRepository;

@GetMapping("/page")
public Page<TeacherInfo> page(Pageable pageable){
    Page<TeacherInfo> list = teacherRepository.findAll(pageable);
    return list;
}

发生了什么 在我开始我的应用程序并使用邮递员发送请求后,我得到了这个: got a 500 error

我调试我的代码,发现这个: child collection is null 图中'classes'是一个list集合,但是是null,没看懂。

下面是我定义的TeacherInfo实体

@Entity
@Table(name = "teacher")
public class TeacherInfo {

@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;

private String name;

private byte age;

private boolean male;

@OneToMany(cascade = CascadeType.ALL,fetch = FetchType.LAZY, mappedBy="chargedTeacher")
private List<ClassInfo> classes = new ArrayList<>();

public void initialize() {
    for (ClassInfo classInfo : classes) {
        classInfo.setChargedTeacher(this);
        for (StudentInfo studentInfo : classInfo.getStudents()) {
            studentInfo.setClassInfo(classInfo);
        }
    }
}
//Setters and Getters}

这是我定义的ClassInfo实体

@Entity
@Table(name = "class_info")
 public class ClassInfo {

@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;

private String name;

private int capacity;

@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "teacher_id",nullable=false)
@JsonIgnore
private TeacherInfo chargedTeacher;

@OneToMany(cascade = CascadeType.ALL,fetch=FetchType.LAZY,mappedBy="classInfo")
private List<StudentInfo> students = new ArrayList<>();

public Long getId() {
    return id;
}

public void setId(Long id) {
    this.id = id;
}

public String getName() {
    return name;
}

public void setName(String name) {
    this.name = name;
}

public int getCapacity() {
    return capacity;
}

public void setCapacity(int capacity) {
    this.capacity = capacity;
}

public TeacherInfo getChargedTeacher() {
    return chargedTeacher;
}

public void setChargedTeacher(TeacherInfo chargedTeacher) {
    this.chargedTeacher = chargedTeacher;
}

public List<StudentInfo> getStudents() {
    return students;
}

public void setStudents(List<StudentInfo> students) {
    this.students = students;
}

}

我认为问题可能来自 Transactionality 和 JPA Fetching 类型。

正在调用您的存储库方法而不是使用事务,这意味着事务位于方法调用的边界上(这可能没有错)。 Spring return 是一个包含对象的页面,但当它尝试序列化它们时,事务已消失,因此无法访问子对象。

我建议将 JPA 关系设置为 EAGER 获取,允许所有对象在事务结束时出现在存储库结果中。

编辑: 回复评论 @豆 public PlatformTransactionManager primaryTransactionManager(EntityManagerFactory 工厂){ return 新的 JpaTransactionManager(工厂); }