为什么在春季启动应用程序的一对多关系中子集合为空?

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了为什么在春季启动应用程序的一对多关系中子集合为空?相关的知识,希望对你有一定的参考价值。

我使用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

我感到困惑,我开始调试我的代码,最后我发现结果的子集合为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'是一个列表集合,但它是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返回一个带有对象的页面,但是当它尝试序列化它们时,事务就消失了,所以无法访问子节点。

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

编辑:回答评论@Bean public PlatformTransactionManager primaryTransactionManager(EntityManagerFactory factory){return new JpaTransactionManager(factory); }

以上是关于为什么在春季启动应用程序的一对多关系中子集合为空?的主要内容,如果未能解决你的问题,请参考以下文章

如何在春季配置多对一和一对多关系? Hibernate会无限调用同一查询

一对多关系,如何匹配非空值

mybatis一对多关联为啥查询不到数据

NHibernate 不会删除一对多关系中的孤儿

根据一对多关系的值对集合进行排序

mybatis 查询一对多 集合中没有值为啥