当前位置: 首页 > 知识库问答 >
问题:

从父项删除时,Spring数据JPA@PreRemoveConcurrentModificationException

李胤
2023-03-14

我有一个参与者可以注册课程的情况。

基本上,我有以下实体配置(省略了getters和setters以及其他无用的属性) :

@Entity
@Table(name = "course")
public class Course {

    @OneToMany(fetch = FetchType.EAGER, cascade = CascadeType.ALL, orphanRemoval = true, mappedBy = "course")
    private Set<Registration> registrations;

}

@Entity
@Table(name = "participant")
public class Participant {

    @OneToMany(fetch = FetchType.LAZY, cascade = CascadeType.ALL, orphanRemoval = true, mappedBy = "participant")
    private Set<Registration> registrations;

}

@Entity
@Table(name = "registration")
public class Registration {

    @ManyToOne(fetch = FetchType.EAGER)
    @JoinColumn(name = "course_id")
    private Course course;

    @ManyToOne(fetch = FetchType.EAGER)
    @JoinColumn(name = "participant_id")
    private Participant participant;

    @PreRemove
    private void removeRegistrationFromHolderEntities() {
        course.getRegistrations().remove(this);
        participant.getRegistrations().remove(this);
    }

}

然后,我可以从视图模型中删除注册或课程(我还删除了不必要的内容):

@Command
public void deleteRegistration(Registration reg) {
    registrationMgr.delete(reg);
}

@Command
public void deleteCourse(Course crs) {
    courseMgr.delete(crs);
}

问题:

    < li >如果我删除注册,我需要< code>@PreRemove函数,以便删除引用。如果没有此项,删除将被忽略(没有错误,只是被忽略) < li >如果我删除课程,我必须移除< code>@PreRemove函数,否则我会得到< code > ConcurrentModificationException (显然...)

我也不能删除引用从delete注册方法(而不是@PreRemove),因为参与者注册是延迟加载(将引发未能延迟初始化角色的集合:…,无法初始化代理-没有会话异常)。

这里最好的方法是什么?

我用Java 11搭配Spring Boot 1.0.4(还有spring-boot-starter-data-jpa)。

编辑:

管理器/存储库或以这种方式定义(对于注册参与者也是如此),因此它应该是事务性的(我的主类上没有@EnableTransactionManagement,但不应该是必需的,因为我不在存储库之外使用事务):

@Transactional
@Component("courseMgr")
public class CourseManager {

    @Autowired
    CourseRepository courseRepository;

    public void saveOrUpdate(Course course) {
        courseRepository.save(course);
    }

    public void delete(Course course) {
        courseRepository.delete(course);
    }
}

public interface CourseRepository extends CrudRepository<Course, Long> {
    ...
}

编辑2:

我想我找到了一个非常简单的解决方案:

我已经从实体中删除了@PreRemove方法,然后没有在 deleteRegistration 方法中删除这样的引用(我已经尝试过但导致无法延迟初始化角色异常集合):

@Command
html" target="_blank">public void deleteRegistration(Registration reg) {
    reg.getCourse().getRegistrations().remove(reg);
    reg.getParticipant.getRegistrations().remove(reg);
    registrationMgr.delete(reg);
}

我只是将parents设置为null,我不在乎它会被删除...

@Command
public void deleteRegistration(Registration reg) {
    reg.setCourse(null);
    reg.setParticipant(null);
    registrationMgr.delete(reg);
}

因此,现在我也可以删除课程,而无需触发@PreRemove中的并发修改异常

编辑3:我的错,注册没有用上面的解决方案删除(仍然没有错误,但没有发生任何事情)。我以这样的方式结束,这终于奏效了:

@Command
public void deleteRegistration(Registration reg) {
    // remove reference from course, else delete does nothing
    Course c = getRegistration().getCourse();
    c.getRegistrations().remove(getRegistration());
    courseMgr.saveOrUpdate(c);

    // delete registration from the database
    registrationMgr.delete(reg);
}

无需从参与者中删除引用…

共有2个答案

薛兴言
2023-03-14

好的解决方案非常简单。

我确实需要从< code>deleteRegistration方法中移除引用。这是我曾经尝试过的,但导致< code >无法延迟初始化角色集合异常:

@Command
public void deleteRegistration(Registration reg) {
    reg.getCourse().getRegistrations().remove(reg);
    reg.getParticipant.getRegistrations().remove(reg);
    registrationMgr.delete(reg);
}

诀窍在于,在尝试删除注册之前,我还必须保存课程实体。

这是有效的:

@Command
public void deleteRegistration(Registration reg) {
    // remove reference from course, else delete does nothing
    Course c = getRegistration().getCourse();
    c.getRegistrations().remove(getRegistration());
    courseMgr.saveOrUpdate(c);

    // delete registration from the database
    registrationMgr.delete(reg);
}

无需从参与者中删除引用…

< code>@PreRemove正在做这项工作,但这样我现在也可以删除课程,而不会触发< code > ConcurrentModificationException 。

谭凯
2023-03-14

您未正确设置存储库。您需要一个用于注册的复合 PK,并且您需要了解双向映射实际上仅用于查询。此外,课程参与中的双向映射带来了挑战,因为默认情况下,通过注册实体的 ManyToOne 关系是 FetchType.EAGER 。有了所有的级联获取注释,你要求JPA对事情进行复杂的组合,看起来你还没有全部解决。从基础知识开始,一定要打印你的SQL语句,如果你想尝试从JPA中获得更多的技巧,从那里开始。

@Entity
@Data
public class Course {
    @Id
    private Integer id;
    private String name;
}

@Entity
@Data
public class Participant {
    @Id
    private Integer id;
    private String name;
}

@Entity
@Data
public class Registration {
    @EmbeddedId
    private RegistrationPK id;

    @ManyToOne
    @MapsId("participant_id")
    private Participant participant;

    @ManyToOne
    @MapsId("course_id")
    private Course course;
}

@Embeddable
@Data
public class RegistrationPK implements Serializable {
    private static final long serialVersionUID = 1L;
    private Integer course_id;
    private Integer participant_id;
}

是您的基本实体注册库需要额外的查询。

public interface RegistrationRepository extends JpaRepository<Registration, RegistrationPK> {
    Set<Registration> findByCourse(Course c);
}

在一个示例中使用所有这些:

@Override
public void run(String... args) throws Exception {
    create();
    Course c = courseRepo.getOne(1);
    Set<Registration> rs = read(c);
    System.out.println(rs);
    deleteCourse(c);
}

private void create() {
    Course c1 = new Course();
    c1.setId(1);
    c1.setName("c1");
    courseRepo.save(c1);

    Participant p1 = new Participant();
    p1.setId(1);
    p1.setName("p1");
    participantRepo.save(p1);

    Registration r1 = new Registration();
    r1.setId(new RegistrationPK());
    r1.setCourse(c1);
    r1.setParticipant(p1);
    registrationRepo.save(r1);
}

private Set<Registration> read(Course c) {
    return registrationRepo.findByCourse(c);
}

private void deleteCourse(Course c) {
    registrationRepo.deleteAll( registrationRepo.findByCourse(c) );
    courseRepo.delete(c);
}
 类似资料:
  • 我正在这里学习“带有链接实体生命周期的双向多对多”教程https://docs.jboss.org/hibernate/orm/5.2/userguide/html_single/hibernate_user_guide.html#associations-many-to-many。但是,我使用的是Spring JPA而不是实体管理器。当我使用repository接口删除一个地址时,这并不是不删除

  • Im使用JPA、MySQL和Spring boot 我一辈子都搞不清楚如何应用级联,文档似乎没有应用我的意图: 例如。https://hellokoding.com/deleting-data-with-jpa-hibernate/使用CascadeType。ALL或CascadeType。删除父实体时,删除子实体的REMOVE属性。它们可以在@OneToOne、@OneTo很多、@ManyToO

  • 我的实体。ValidationStep与documentDetail有一对一的关系,documentDetail与documentValidations有一个完全的关系 我的删除查询 父ValidationStep被删除,但是docDetail和documentValidations仍然在数据库中。

  • 在我的项目中,我使用Spring数据jpa。我有多对多关系的表格。我的实体: 和零件: 现在在Controller中,我尝试从表部分中删除一行: 但我有例外: 区分完整性约束冲突:“FK9Y4MKICYBLJWPENACP4298I49:PUBLIC.PARTS外键(ID\u导出)引用PUBLIC.EXPORT(ID)(1)”;SQL语句:/*删除com.aleksandr0412.demo.en

  • DataUpload实体 DataUpload存储库 为了删除数据上传,我尝试执行存储库的两个查询方法:

  • 问题内容: 假设我们有3个Entities对象类: 如何使用JPA2.x(或hibernate)批注来: 父级删除时(一对多)自动删除所有子级 删除后自动从子级列表中删除子级(多对一) 儿童删除时(一对一)自动删除玩具 我正在使用Hibernate 4.3.5和mysql 5.1.30。 谢谢 问题答案: 如本文所述, 实体状态转换应从父级到子级联,而不是相反。 您需要这样的东西: