问题场景
这个问题一般是在spring JPA中使用级联,是发生在@ManyToOne这一方,即子方。
例如:
父方
// An highlighted block
@Getter
@Setter
@Entity
@Audited
@Table(name = "question_sets")
public class QuestionSetEntity extends AbstractAuditEntity implements Versional, Normalizable {
@Id
@Column(name = "id")
@GeneratedValue(strategy = GenerationType.IDENTITY)
long id;
@Column(name = "version")
int version = 0;
@Column(name = "title")
String title = "";
@Column(name = "description")
String description = "";
@ElementCollection
@CollectionTable(
name = "question_set_tags",
joinColumns = @JoinColumn(name = "set")
)
@Column(name = "tag")
Set<String> tags = new HashSet<>();
@OneToMany(mappedBy = "set", cascade = CascadeType.ALL, orphanRemoval = true)
List<QuestionEntity> questions = new ArrayList<>();
@NotAudited
@OneToMany(mappedBy = "set", cascade = CascadeType.ALL, orphanRemoval = true)
List<QuestionSetStarEntity> stars = new ArrayList<>();
@Override
public void normalize() {
this.questions.forEach(q -> q.setSet(this));
this.stars.forEach(q -> q.setSet(this));
}
子方
// An highlighted block
@Getter
@Setter
@Entity
@Audited
@Table(name = "questions")
public class QuestionEntity {
@Id
@Column(name = "id")
@GeneratedValue(strategy = GenerationType.IDENTITY)
long id;
@ManyToOne
@JoinColumn(name = "set")
QuestionSetEntity set;
@Column(name = "index")
int index = 0;
@Column(name = "description")
String description = "";
@Column(name = "answer")
String answer = "";
}
子方存在引用父方的外键,即
@ManyToOne
@JoinColumn(name = “set”)
QuestionSetEntity set;
一般子方不能影响父方,所以@mantToMany注解里一般不加任何级联设置。
问题的发生
当前写法没有问题
而如果
将QuestionSetEntity set;
改成 QuestionSetEntity set = new QuestionSetEntity();时
在下面这个场景中就会出现标题中的错误
场景:对父方的修改中设计到对子方的增删改并启动了事务
原因
因为上述的操作设计到了父表和子表,又由于开启了事务,所以当提交子表操作的事务时,父方还没有save,把还没有save的对象保存到子方new出来的外键时再来提交就会报错。
解决方法
1、关闭事务,这样对父表的save就会先提交。
2、在@ManyToOne注解上添加级联设置(cascade = CascadeType.PERSIST)(不推荐,这样会导致子方影响父方的后果)
3、就如同上方代码那样,不要new,默认为null。