2

 多対多の関係には、Person と Vehicle の 2 つのクラスがあります。新しい人物が作成された場合、または既存の人物のレコードが更新された場合 (例: Vehicle レコードが追加された場合)、既存の Vehicle レコードが存在する場合はそれを使用することが望ましいでしょう。

 問題は、それをどのように達成するかです。更新または挿入できるスレッドが多数あるため、挿入または更新の前にクエリを実行することはできません。

 この時点で、アプリケーションは一意の制約例外をチェックし、キャッチされると、新しい既存の Vehicle オブジェクトが、「登録」列によってデータベースからクエリされたオブジェクトに置き換えられます。このソリューションは機能していますが、Vehicle レコードごとに個別のセッションを作成する必要があるため、少し扱いに​​くいようです。

休止状態の注釈によって目的の動作を実現する方法はありますか? または完全に異なるソリューションですか?ありがとう。

@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;
  ...
4

1 に答える 1

1

更新または挿入できるスレッドが多数あるため、挿入または更新の前にクエリを実行することはできません。

しかし、これはそれを行う方法です。

パフォーマンスの問題である場合 (私はそうは思いません)、2 次キャッシュの使用を検討してください。セッションにバインドされており、スレッドごとに少なくとも 1 つのセッションが必要であるため、最初のレベルではこれを処理できません。

そして、 と の両方にバージョン列が必要PersonですVehicle

アプリケーションには、すでに次の問題があります。 1. ユーザー A が Person レコードをロードします。2. ユーザー B が同じ Person レコードをロードします。3. ユーザー A が電話番号を変更し、個人レコードを保存します。4. ユーザー B が Address を変更し、Person レコードも保存します。=> 結果: ユーザー A の変更 (電話番号の変更) は上書きされ、レコードには古い電話番号が記録され、この問題について誰も通知されません。

バージョン列はこの問題を回避します。バージョン列がある場合、ステップ 4 で Hibernate はその間にレコードが変更されたことを検出し、例外をスローします。この例外をキャッチし、ユーザー B にレコードをリロードして住所変更をやり直すように指示する必要があります。これにより、ユーザー B に少し余分な作業が必要になりますが (このケースはめったに発生しないため、それほど多くはありません)、情報が失われることはなく、データベースには正しい情報が含まれています。

最初の読み取りでレコードが見つからなかったときに同じことをしなければなりませんが、挿入時に制約違反がキャッチされます。すでにこのエラーをキャッチしていますが、ユーザーに通知していないため、おそらく行う必要があります。

アプリケーションロジックがこのケースを処理する必要があるため (たとえば、ユーザーに通知するなど)、Hibernate レベルで簡単な解決策はありません。

于 2013-01-18T10:37:59.550 に答える