Spring Data和Hibernate中不受控制的删除
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Spring Data和Hibernate中不受控制的删除相关的知识,希望对你有一定的参考价值。
我不是Hibernate的专家,所以我的问题可能是微不足道的。
我正在为一个活动写一个预订引擎。使用引擎,可以进行注册,每个注册都有一定数量的参与者。每个注册都可以关联一个或多个付款。
对于每次注册,可以对房间进行多次预订。预订可以是房间的一部分(例如,对于想要共享四人房的两个参与者的预订)或整个房间。每个房间可以具有与特定房间类型相对应的多个房间布置(例如,四倍,三倍或双倍)。预订完成后,所选房型和房间通过与预订相关的房间分配进行连接。
要在Spring中编写代码,我已经设置了这些模型类:
registration.Java
@Entity
@Table(name = "registrations")
@Data
public class Registration {
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
@Column(name = "id")
private Long id;
// other fields
}
participant.Java
@Entity
@Table(name = "participants")
@Data
public class Participant {
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
@Column(name = "id")
private Long id;
@ManyToOne(targetEntity = Registration.class)
@JoinColumn(name = "registration_id")
private Registration registration;
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "reservation_id")
private Reservation reservation;
// other fields
}
reservation.Java
@Entity
@Table(name = "reservations")
@Data
public class Reservation {
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
@Column(name = "id")
private Long id;
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "room_assignment_id")
private RoomAssignment roomAssignment;
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "registration_id")
private Registration registration;
@OneToMany(fetch = FetchType.LAZY)
@JoinColumn(name = "reservation_id")
private List<Participant> participants;
// other fields
}
room assignment.Java
@Entity
@Table(name = "room_assignments")
@Data
public class RoomAssignment {
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
@Column(name = "id")
private Long id;
@OneToOne(fetch = FetchType.LAZY, mappedBy = "assignment", cascade = CascadeType.ALL)
private Room room;
@OneToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "room_type_id", nullable = false)
private RoomType roomType;
@OneToMany(fetch = FetchType.LAZY)
@JoinColumn(name = "room_assignment_id")
private List<Reservation> reservations;
}
room.Java
@Entity
@Table(name = "rooms")
@Data
public class Room {
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
@Column(name = "id")
private Long id;
@Column(name = "room_name")
private String roomName;
@OneToMany(fetch = FetchType.LAZY )
@JoinColumn(name = "room_id")
private List<RoomArrangement> roomArrangements;
@OneToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "assignment_id")
private RoomAssignment assignment;
}
最后,RoomArrangement.java
@Entity
@Table(name = "room_arrangements")
@Data
public class RoomArrangement {
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
@Column(name = "id")
private Long id;
@ManyToOne(targetEntity = RoomType.class)
@JoinColumn(name = "room_type_id", nullable = false)
private RoomType roomType;
@ManyToOne(targetEntity = Room.class)
@JoinColumn(name = "room_id", nullable = false)
private Room room;
@Column(name = "priority")
private Integer priority;
}
所有模型类都有相应的Repository类,我不会在这里添加它们,因为它们只包含方法名称,您可以从代码中看到它们。
我目前正在编写删除注册的程序。为此,我删除了所有参与者和所有付款,然后对于每个预订,我看看它是否是相应房间分配的唯一一个,在这种情况下我也取消了房间分配,并且我取消了预订,最后注册。我用这种方法编写了这部分:
@Override
public void deleteRegistration(Registration registration) {
// Deleting payments
paymentRepository.deleteAll(paymentRepository.findByRegistration(registration));
// Deleting participants
participantRepository.deleteAll(participantRepository.findByRegistration(registration));
List<Reservation> reservations = reservationRepository.findByRegistration(registration);
for (Reservation res : reservations) {
RoomAssignment assignment = roomAssignmentRepository.findByReservationsContains(res);
if (reservationRepository.findByRoomAssignment(assignment).size() == 1) {
reservationRepository.delete(res);
Room room = roomRepository.findByAssignment(assignment);
room.setAssignment(null);
roomRepository.save(room);
roomAssignmentRepository.delete(assignment);
} else {
reservationRepository.delete(res);
}
}
registrationRepository.delete(registration);
}
结果很奇怪:当执行到达roomAssignmentRepository.delete(赋值)时; call,它打破了带有消息的DataIntegrityViolationException
Column 'room_id' cannot be null
我试图记录hibernate调用,其中一个对我来说绝对是奇怪的。
在这里,我列出了相应的java调用
paymentRepository.deleteAll(此注册没有付款)
select payment0_.id as id1_1_, payment0_.amount as amount2_1_, payment0_.paypal_order_id as paypal_o3_1_, payment0_.registration_id as registra5_1_, payment0_.type as type4_1_ from payments payment0_ where payment0_.registration_id=?
participantRepository.deleteAll
select participan0_.id as id1_0_, participan0_.birth_date as birth_da2_0_, participan0_.birth_place as birth_pl3_0_, participan0_.email as email4_0_, participan0_.facebook_profile as facebook5_0_, participan0_.first_name as first_na6_0_, participan0_.first_time as first_ti7_0_, participan0_.food_intolerances as food_int8_0_, participan0_.food_preferences as food_pre9_0_, participan0_.gender as gender10_0_, participan0_.last_name as last_na11_0_, participan0_.other_food_notes as other_f12_0_, participan0_.registration_id as registr13_0_, participan0_.reservation_id as reserva14_0_ from participants participan0_ where participan0_.registration_id=?
delete from participants where id=?
reservationRepository.findByRegistration
select reservatio0_.id as id1_3_, reservatio0_.monday as monday2_3_, reservatio0_.registration_id as registra4_3_, reservatio0_.room_assignment_id as room_ass5_3_, reservatio0_.thursday as thursday3_3_ from reservations reservatio0_ where reservatio0_.registration_id=?
roomAssignmentRepository.findByReservationsContains
select roomassign0_.id as id1_5_, roomassign0_.room_type_id as room_typ2_5_ from room_assignments roomassign0_ where ? in (select reservatio1_.id from reservations reservatio1_ where roomassign0_.id=reservatio1_.room_assignment_id)
select room0_.id as id1_7_0_, room0_.assignment_id as assignme3_7_0_, room0_.room_name as room_nam2_7_0_ from rooms room0_ where room0_.assignment_id=?
reservationRepository.delete
select reservatio0_.id as id1_3_, reservatio0_.monday as monday2_3_, reservatio0_.registration_id as registra4_3_, reservatio0_.room_assignment_id as room_ass5_3_, reservatio0_.thursday as thursday3_3_ from reservations reservatio0_ where reservatio0_.room_assignment_id=?
update participants set reservation_id=null where reservation_id=?
delete from reservations where id=?
roomRepository.findByAssignment
select room0_.id as id1_7_, room0_.assignment_id as assignme3_7_, room0_.room_name as room_nam2_7_ from rooms room0_ where room0_.assignment_id=?
room repository.save
update rooms set assignment_id=?, room_name=? where id=?
roomAssignmentRepository.delete
update reservations set room_assignment_id=null where room_assignment_id=?
update room_arrangements set room_id=null where room_id=?
最后更新room_arrangements设置room_id = null其中room_id =?当然,SQL更新打破了非空约束。
经过这么长时间的准备,问题是:为什么Hibernate正在进行最后一次更新,因为我没有以任何方式修改任何room_arrangement?在该调用的那一刻,我正在修改RoomAssignment类,它甚至没有连接到RoomArrangement。
可爱。通过写下这个问题,我意识到,正如我们在意大利所说,魔鬼在细节上。
从互联网示例中复制和粘贴内容使我错误地注释了RoomAssignment和Room之间的关系。
@OneToOne(fetch = FetchType.LAZY, mappedBy = "assignment", cascade = CascadeType.ALL)
private Room room;
当然,问题与CascadeType.ALL有关:当我删除作业时,Hibernate会尝试删除Room,当它这样做时,它会通过清除外键来清理RoomType - 这当然会导致错误。
我可以接受的教训是:从互联网上复制粘贴时要小心:)
以上是关于Spring Data和Hibernate中不受控制的删除的主要内容,如果未能解决你的问题,请参考以下文章
spring.jpa.hibernate.ddl-auto=create 在带有 SpringBoot 2.0 的 Hibernate 5 中不起作用
HIbernate 批量插入或更新在 Spring Boot 中不起作用
Spring Security with hibernate:hasRole() 在配置中不起作用
在 JPA/Hibernate 中使用 @OnetoMany 的实体中不存在时从数据库中删除子记录(Spring 引导应用程序)