为什么 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(工厂);
}
我使用 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(工厂); }