Spring Boot+Hibernate保存员工时JpaSystemException异常求助
调用/save/employee接口保存员工信息时抛出如下异常:
org.springframework.orm.jpa.JpaSystemException: Error accessing field [private com.example.hibernatespringboot.entities.Address com.example.hibernatespringboot.entities.Employee.address] by reflection for persistent property [com.example.hibernatespringboot.entities.Employee#address] : com.example.hibernatespringboot.entities.Employee@7a329261; nested exception is org.hibernate.property.access.spi.PropertyAccessException: Error accessing field [private com.example.hibernatespringboot.entities.Address com.example.hibernatespringboot.entities.Employee#address] by reflection for persistent property [com.example.hibernatespringboot.entities.Employee#address]
项目代码
启动类 HibernateSpringBootApplication.class
package com.example.hibernatespringboot; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.EnableAutoConfiguration; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.boot.autoconfigure.domain.EntityScan; @SpringBootApplication @EnableAutoConfiguration @EntityScan(basePackages= {"com.example.hibernatespringboot"}) public class HibernateSpringBootApplication { public static void main(String[] args) { SpringApplication.run(HibernateSpringBootApplication.class, args); } }
实体类
Employee 实体类
package com.example.hibernatespringboot.entities; import javax.persistence.CascadeType; import javax.persistence.Column; import javax.persistence.Entity; import javax.persistence.GeneratedValue; import javax.persistence.GenerationType; import javax.persistence.Id; import javax.persistence.JoinColumn; import javax.persistence.OneToOne; import javax.persistence.Table; @Table @Entity public class Employee { @Id @GeneratedValue(strategy=GenerationType.IDENTITY) @Column(name="id") private Integer id; @Column(name="firstname") private String firstname; @Column(name="age") private Integer age; @OneToOne(cascade=CascadeType.ALL) @JoinColumn(name="address_id") private Address address; public Integer getId() { return id; } public void setId(Integer id) { this.id = id; } public String getFirstname() { return firstname; } public void setFirstname(String firstname) { this.firstname = firstname; } public Integer getAge() { return age; } public void setAge(Integer age) { this.age = age; } public Address getAddress() { return address; } public void setAddress(Address address) { this.address = address; } public Employee() { } public Employee(String firstname, Integer age) { super(); this.firstname = firstname; this.age = age; } }
Address 实体类
package com.example.hibernatespringboot.entities; import javax.persistence.Column; import javax.persistence.Entity; import javax.persistence.GeneratedValue; import javax.persistence.GenerationType; import javax.persistence.Id; import javax.persistence.Table; @Entity @Table public class Address { @Id @GeneratedValue(strategy=GenerationType.IDENTITY) @Column(name="id") private Integer id; @Column(name="pincode") private String pincode; public Address() { } public Address(String pincode) { super(); this.pincode = pincode; } public Integer getId() { return id; } public void setId(Integer id) { this.id = id; } public String getPincode() { return pincode; } public void setPincode(String pincode) { this.pincode = pincode; } }
HibernateUtil 类
package com.example.hibernatespringboot.helper; import org.hibernate.SessionFactory; import org.hibernate.cfg.Configuration; import com.example.hibernatespringboot.entities.Address; import com.example.hibernatespringboot.entities.Employee; public class HibernateUtil { private static SessionFactory sessionFactory; static { sessionFactory = new Configuration() .configure("hibernate.cfg.xml") .addAnnotatedClass(Employee.class) .addAnnotatedClass(Address.class) .buildSessionFactory(); } public static SessionFactory getSessionFactory() { return sessionFactory; } }
EmployeeRepository 类
package com.example.hibernatespringboot.repositories; import org.hibernate.Session; import org.hibernate.SessionFactory; import org.hibernate.Transaction; import org.springframework.stereotype.Repository; import com.example.hibernatespringboot.entities.Address; import com.example.hibernatespringboot.entities.Employee; import com.example.hibernatespringboot.helper.HibernateUtil; @Repository public class EmployeeRepository { public Integer saveEmployee() { SessionFactory sessionFactory = HibernateUtil.getSessionFactory(); Session session = null; Integer id = null; try { Employee employee = new Employee("Mridul", 23); Address address = new Address("123456"); employee.setAddress(address); session = sessionFactory.openSession(); Transaction tx = session.beginTransaction(); session.save(employee); tx.commit(); } finally { if(session != null) session.close(); } return id; } }
EmployeeService 类
package com.example.hibernatespringboot.services; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; import com.example.hibernatespringboot.repositories.EmployeeRepository; @Service public class EmployeeService { @Autowired EmployeeRepository employeeRepository; public Integer saveEmployee() { Integer id = null; id = employeeRepository.saveEmployee(); return id; } }
EmployeeController 类
package com.example.hibernatespringboot.controllers; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.http.HttpStatus; import org.springframework.http.ResponseEntity; import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.RestController; import com.example.hibernatespringboot.services.EmployeeService; @RestController public class EmployeeController { @Autowired EmployeeService employeeService; @PostMapping("/save/employee") public ResponseEntity<Integer> saveEmployee(){ Integer id = employeeService.saveEmployee(); HttpStatus status = id!=null?HttpStatus.CREATED:HttpStatus.NO_CONTENT; return new ResponseEntity<>(id, status); } }
hibernate.cfg.xml 配置文件
<!DOCTYPE hibernate-configuration PUBLIC "-//Hibernate/Hibernate Configuration DTD 3.0//EN" "http://www.hibernate.org/dtd/hibernate-configuration-3.0.dtd"> <hibernate-configuration> <session-factory> <!-- JDBC Database connection settings --> <property name="connection.driver_class">org.postgresql.Driver</property> <property name="connection.url">jdbc:postgresql://localhost:5432/test-hibernate</property> <property name="connection.username">postgres</property> <property name="connection.password">root</property> <!-- JDBC connection pool settings ... using built-in test pool --> <property name="connection.pool_size">1</property> <!-- Select our SQL dialect --> <property name="dialect">org.hibernate.dialect.PostgreSQLDialect</property> <!-- Echo the SQL to stdout --> <property name="show_sql">true</property> <property name="hibernate.hbm2ddl.auto">update</property> </session-factory> </hibernate-configuration>
application.properties 配置文件
spring.datasource.url=jdbc:postgresql://localhost:5432/test-hibernate spring.datasource.username=postgres spring.datasource.password=root spring.datasource.driver-class-name=org.postgresql.Driver spring.jpa.properties.hibernate.dialect = org.hibernate.dialect.PostgreSQLDialect
问题原因及解决方案
核心原因
项目同时启用了Spring Boot自动配置的JPA上下文和自定义HibernateUtil创建的独立SessionFactory,导致实体类被两个不同的Hibernate实例加载,反射访问字段时出现类加载冲突。另外EmployeeRepository中未给返回的id赋值,导致接口始终返回null。
解决方案
方案一:移除自定义HibernateUtil,使用Spring JPA的EntityManager
- 删除
HibernateUtil类 - 修改
EmployeeRepository,通过@PersistenceContext注入EntityManager:
package com.example.hibernatespringboot.repositories; import javax.persistence.EntityManager; import javax.persistence.PersistenceContext; import javax.transaction.Transactional; import org.springframework.stereotype.Repository; import com.example.hibernatespringboot.entities.Address; import com.example.hibernatespringboot.entities.Employee; @Repository @Transactional public class EmployeeRepository { @PersistenceContext private EntityManager entityManager; public Integer saveEmployee() { Employee employee = new Employee("Mridul", 23); Address address = new Address("123456"); employee.setAddress(address); entityManager.persist(employee); return employee.getId(); } }
方案二:改用Spring Data JPA(更推荐)
- 创建
EmployeeRepository接口继承CrudRepository:
package com.example.hibernatespringboot.repositories; import org.springframework.data.repository.CrudRepository; import org.springframework.stereotype.Repository; import com.example.hibernatespringboot.entities.Employee; @Repository public interface EmployeeRepository extends CrudRepository<Employee, Integer> { }
- 修改
EmployeeService:
package com.example.hibernatespringboot.services; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; import com.example.hibernatespringboot.entities.Employee; import com.example.hibernatespringboot.entities.Address; import com.example.hibernatespringboot.repositories.EmployeeRepository; @Service public class EmployeeService { @Autowired EmployeeRepository employeeRepository; public Integer saveEmployee() { Employee employee = new Employee("Mridul", 23); Address address = new Address("123456"); employee.setAddress(address); Employee savedEmployee = employeeRepository.save(employee); return savedEmployee.getId(); } }
- 删除
HibernateUtil类,无需手动管理Session和事务,Spring会自动处理。
额外配置
在application.properties中添加JPA自动建表配置(按需选择):
spring.jpa.hibernate.ddl-auto=update
内容的提问来源于stack exchange,提问作者Mridul Rajbhar

