【发布时间】:2018-07-05 13:27:46
【问题描述】:
有 2 个实体(比如说规则和标签)使用链接实体具有多对多关系
as per hibernate reference documentation
规则实体:
@Entity
@Table(name = "rule")
@JsonIdentityInfo(
generator = ObjectIdGenerators.PropertyGenerator.class,
property = "name")
public class Rule implements Serializable {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
@NaturalId
@NotBlank
@Column(unique = true)
private String name;
@Lob
@Column(columnDefinition = "TEXT")
private String content;
@OneToMany(mappedBy = "rule", cascade = {CascadeType.PERSIST,
CascadeType.MERGE})
private List<RuleLabel> labels = new ArrayList<>();
...
标签实体:
@Entity
@Table(name = "label")
@JsonIdentityInfo(
generator = ObjectIdGenerators.PropertyGenerator.class,
property = "id")
public class Label implements Serializable {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
@NotBlank
private String name;
@OneToMany(mappedBy = "label", cascade = {CascadeType.PERSIST,
CascadeType.MERGE})
private List<RuleLabel> rules = new ArrayList<>();
...
链接实体:
@Entity
public class RuleLabel implements Serializable {
@Id
@ManyToOne
private Rule rule;
@Id
@ManyToOne
private Label label;
...
存储库:
@Repository
public interface LabelRepository extends JpaRepository<Label, Long>
...
@Repository
public interface RuleRepository extends JpaRepository<Rule, Long>
...
通过 RuleRepository.save(Rule) 创建新实体可以正常工作,但是当我尝试更新现有实体时(相同的方法 RuleRepository.save(Rule),但实体要保存的包含 id 字段)它会导致 Hibernate: select... 查询的无限循环:
Hibernate: select rule0_.id as id1_7_1_, rule0_.is_active as is_activ2_7_1_, rule0_.content as content3_7_1_, rule0_.is_deleted as is_delet4_7_1_, rule0_.import_section as import_s5_7_1_, rule0_.name as name6_7_1_, rule0_.rule_configuration as rule_con7_7_1_, labels1_.rule_id as rule_id1_8_3_, labels1_.label_id as label_id2_8_3_, labels1_.rule_id as rule_id1_8_0_, labels1_.label_id as label_id2_8_0_ from rule rule0_ left outer join rule_label labels1_ on rule0_.id=labels1_.rule_id where rule0_.id=?
结果是 StackOverflowError
java.lang.StackOverflowError: null
at com.mysql.jdbc.ServerPreparedStatement.getInstance(ServerPreparedStatement.java:332)
...
(LabelRepository 的行为方式相同)
如何修复?
更新:
将获取策略更改为 Lazy 后
@Id
@ManyToOne(fetch = FetchType.LAZY)
private Rule rule;
@Id
@ManyToOne(fetch = FetchType.LAZY)
private Label label;
无限循环问题已经解决,但出现了新问题 - 相关实体没有被填充并且当 Hibernate 尝试将值插入链接表时
Hibernate: insert into rule_label (rule_id, label_id) values (?, ?)
我们得到
org.springframework.dao.DataIntegrityViolationException: could not execute statement; SQL [n/a]; constraint [null]; nested exception is org.hibernate.exception.ConstraintViolationException: could not execute statement
...
Caused by: com.mysql.jdbc.exceptions.jdbc4.MySQLIntegrityConstraintViolationException: Column 'rule_id' cannot be null
【问题讨论】:
-
这两个实体的代码粘贴时间太长了吧?...
-
对不起,我的错。添加代码sn-ps,谢谢。
-
您是否有 toString 或打印出递归关系、RuleLabel 列表和标签的东西?
-
当您询问导致特定异常的特定代码段时,请发布该代码,并发布异常堆栈跟踪。否则,我们只能猜测。
-
只是一个猜测:如果你覆盖它,删除你的 toString() 方法。
标签: java hibernate spring-data-jpa