Spring Boot保存Employee时出现非空属性引用空值错误排查
我定义了如下Employee实体:
@Entity @Data @NoArgsConstructor @AllArgsConstructor @Getter @Setter @JsonIdentityInfo(generator = ObjectIdGenerators.PropertyGenerator.class, property = "id") public class Employee { @Id @GeneratedValue(strategy = GenerationType.IDENTITY) @Column(name = "id") private Integer id; private String firstname; private String lastname; @DateTimeFormat(pattern = "yyyy-MM-dd") private Date dateOfBirth; private String city; private String address; private String phone; private String mobile; private String email; private String photo; private String username; @DateTimeFormat(pattern = "yyyy-MM-dd") private Date hireDate; @OneToMany @JoinColumn(name = "teamsId", updatable = false, insertable = false) private List<Teams> teams; private Integer teamsId; }
Repository层代码:
@Repository public interface EmployeeRepository extends JpaRepository<Employee, Integer> { }
Service层代码:
@Service public class EmployeeService { @Autowired private EmployeeRepository employeeRepository; public Employee saveEmployeeAndReturnId(Employee employee){ return employeeRepository.saveAndFlush(employee); } }
Controller层代码片段:
@Autowired private EmployeeService employeeService; @PostMapping("/users/addNew") public RedirectView addNew(Employee employee, RedirectAttributes redirectAttributes){ System.out.println(employee.toString()); Employee newEmployee = employeeService.saveEmployeeAndReturnId(employee); System.out.println(newEmployee.getId().toString());
执行后打印的Employee对象信息:
Employee(id=null, firstname=user, lastname=useruser, dateOfBirth=Tue Aug 24 00:00:00 CEST 1999, city=A, address=A, phone=A, mobile=add, email=user@gmail.com, photo=null, username=userr, hireDate=null, teams=null, teamsId=null)
同时出现如下错误:
2022-10-07 12:41:49.420 ERROR 11388 --- [nio-8081-exec-2] o.a.c.c.C.[.[.[/].[dispatcherServlet] : Servlet.service() for servlet [dispatcherServlet] in context with path [] threw exception [Request processing failed; nested exception is org.springframework.dao.DataIntegrityViolationException: not-null property references a null or transient value : com.mk.atmosfera.hr.models.Employee._employee_employeeIdBackref; nested exception is org.hibernate.PropertyValueException: not-null property references a null or transient value : com.mk.atmosfera.hr.models.Employee._employee_employeeIdBackref] with root cause
org.hibernate.PropertyValueException: not-null property references a null or transient value : com.mk.atmosfera.hr.models.Employee._employee_employeeIdBackref
我并未在任何地方创建employee_id字段,但该字段却出现了,请问这个错误的原因是什么?我哪里出错了?
错误原因
这个错误源于双向关联的非空约束冲突,_employee_employeeIdBackref是Hibernate自动生成的反向关联字段,对应Teams实体中指向Employee的@ManyToOne关联。
核心问题有两点:
Teams实体中应该存在@ManyToOne(optional = false)的配置(强制要求每个Teams必须绑定一个Employee),但你当前保存的Employee对象中teams为null,导致Hibernate检测到反向关联的非空约束被违反。Employee中的@OneToMany配置逻辑混乱:@JoinColumn(name = "teamsId")指定的是Teams表中指向Employee的外键字段,但你却在Employee实体中定义了teamsId字段——外键字段本应放在关联关系中"多"的一方(Teams),而非"一"的一方(Employee)。insertable = false, updatable = false设置意味着该外键不由Employee维护,但结合Teams的非空关联要求,保存时Hibernate无法生成合法的关联数据,触发错误。
解决方法
方法1:修正双向关联配置(推荐)
- 删除
Employee中的private Integer teamsId;字段,外键字段应放在Teams实体中。 - 修改
Employee的@OneToMany配置,用mappedBy指定关联的维护方(即Teams中的关联字段):@OneToMany(mappedBy = "employee") private List<Teams> teams; - 检查
Teams实体的关联配置:- 如果不需要强制
Teams必须关联Employee,去掉@ManyToOne的optional = false(默认optional = true,允许关联为空):@ManyToOne @JoinColumn(name = "employee_id") // Teams表中指向Employee.id的外键字段 private Employee employee; - 如果确实需要强制关联,保存
Employee时必须同时传入已持久化的Teams对象,或先保存Teams再建立关联。
- 如果不需要强制
方法2:改为单向关联
如果不需要双向关联,直接调整Employee的@OneToMany配置,明确指定Teams表中的外键:
@OneToMany @JoinColumn(name = "employee_id") // Teams表中用于关联Employee的外键字段 private List<Teams> teams;
同时确保Teams实体中没有定义反向的@ManyToOne关联,或把反向关联的optional设为true。
内容的提问来源于stack exchange,提问作者quwertysokman

