java - 如何在多对多关系中使用现有记录并避免违反唯一约束( hibernate )

标签 java hibernate many-to-many unique-constraint

有两个类,Person 和 Vehicle,是多对多关系。如果创建新人员或更新现有人员的记录(例如添加车辆记录),则最好使用现有车辆记录(如果存在)。

问题是如何实现它。插入或更新之前的查询不是一个选项,因为有许多线程可以更新或插入。

此时,应用程序检查唯一约束异常,当它被捕获时,新的现有 Vehicle 对象将替换为通过“注册”列从数据库中查询的对象。该解决方案有效,但它似乎有点笨拙,因为必须为每个车辆记录创建一个单独的 session 。

有什么方法可以通过 hibernate 注释实现所需的行为吗?还是完全不同的解决方案?谢谢。

@Entity
@Table(name="PERSON", uniqueConstraints = { @UniqueConstraint(columnNames = "name", name="NAME_KEY") })
public class Person  implements Serializable {
  private static final long serialVersionUID = 3507716047052335731L;

  @Id
  @GeneratedValue(strategy=GenerationType.SEQUENCE, generator="PersonIdSeq")
  @SequenceGenerator( name = "PersonIdSeq", sequenceName="PERSON_ID_SEQ")
  private Long id;

  @Index(name="PERSON_NAME_IDX")
  private String name;

  @ManyToMany(targetEntity=Vehicle.class, cascade={CascadeType.PERSIST, CascadeType.MERGE})
  @JoinTable(name="PERSON_VEHICLE_LNK", joinColumns=@JoinColumn(name="PERSON_ID"),inverseJoinColumns=@JoinColumn(name="VEHICLE_ID"),
     uniqueConstraints = { @UniqueConstraint(columnNames = {"PERSON_ID", "VEHICLE_ID"}, name="person_vehicle_lnk_key")})
  @GeneratedValue(strategy=GenerationType.SEQUENCE, generator="PersonVehicleLnkIdSeq")
  @SequenceGenerator(name = "PersonVehicleLnkIdSeq", sequenceName="PERSON_VEHICLE_LNK_ID_SEQ")
  @CollectionId(columns = @Column(name="ID"), type=@Type(type="long"), generator = "PersonVehicleLnkIdSeq")
  private List<Vehicle> vehicle = new ArrayList<>();
  ...

@Entity
@Table( name = "VEHICLE", uniqueConstraints = {@UniqueConstraint(columnNames="registration", name="REGISTRATION_KEY")}  )
public class Vehicle implements Serializable {
  private static final long serialVersionUID = -5592281235230216382L;

  @Id
  @GeneratedValue(strategy=GenerationType.SEQUENCE, generator="VehicleIdSeq")
  @SequenceGenerator( name = "VehicleIdSeq", sequenceName="VEHICLE_ID_SEQ")
  private Long id;

  @Index(name="REGISTRATION_IDX")
  private String registration;
  ...

最佳答案

A query prior the insert or update is not an option because there are many threads which can update or insert.

但这是怎么做的。

如果这是一个性能问题(我不这么认为)然后考虑使用二级缓存。第一级无法处理此问题,因为它绑定(bind)到一个 session ,并且每个线程至少需要一个 session 。

然后您需要在 PersonVehicle 中都有一个版本列。

在您的应用程序中,您已经遇到以下问题: 1. 用户 A 加载一个 Person 记录。 2. 用户 B 加载相同的 Person 记录。 3. 用户A修改电话号码,保存个人记录。 4.用户B修改Address,同时保存Person记录。 => 结果:用户A的修改(电话号码更改)被覆盖,记录有旧电话号码,没有人知道这个问题。

版本列避免了这个问题。当有版本列时,在步骤 4 中 Hibernate 发现记录同时被修改并抛出异常。必须捕获此异常,并且必须告知用户 B 重新加载记录并重做他的地址更改。这迫使用户 B 做一些额外的工作(不多,因为这种情况很少发生),但不会丢失任何信息,并且数据库包含正确的信息。

当第一次读取时没有找到记录时,您必须做同样的事情,但在插入时发现约束违规。您已经发现了这个错误,但您没有通知用户,您可能应该这样做。

在 Hibernate 级别对此没有简单的解决方案,因为应用程序逻辑必须处理这种情况(例如通知用户)。

关于java - 如何在多对多关系中使用现有记录并避免违反唯一约束( hibernate ),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/14396501/

相关文章:

symfony - 管理中的可排序奏鸣曲类型模型

mysql - SQL 查询以匹配具有/不具有所有定义的多对多匹配项的记录

java - 如何在 java.util.Date 中获取当前季度的第一个日期和最后一个日期

java - 当鼠标在 JTextarea 上移动时,JTextarea 会闪烁

java - 在 Java 中使用 SQL 设置值

java - 计时器停止应用程序

java - 无法执行语句更新

java - hibernate ;高质量语言;为什么删除查询不起作用,但选择呢?

java - RequestContextHolder.getRequestAttributes() null - Spring Security + Multi-Tenancy

database - 现场冲突的django related_name