レガシ コードの問題により、一意のインデックスを手動で計算する必要があり、データベースに新しい行を挿入するときに auto_increment を使用できません。
問題は、複数のクライアント (異なるマシン) の複数の挿入が同時に発生する可能性があることです。したがって、現在のトランザクションがアクティブな間、他のトランザクションによって読み取られないように、最高の ID を持つ行をロックする必要があります。または、読み取りからテーブル全体をロックすることもできます。この場合、書き込み/読み取りは非常にまれであるため (1 秒あたり 1 オペレーション未満)、時間は問題になりません。
分離レベルを 8 (Serializable) に設定しようとしましたが、MySQL は DeadLockException をスローします。興味深いことに、次の ID を決定するための SELECT がまだ実行されています。これは、シリアル化可能についての私の理解と矛盾しています。
また、選択の PESSIMISTIC_READ に LockMode を設定しても、役に立たないようです。
public void insert(T entity) {
EntityManager em = factory.createEntityManager();
try {
EntityTransaction transaction = em.getTransaction();
try {
transaction.begin();
int id = 0;
TypedQuery<MasterDataComplete> query = em.createQuery(
"SELECT m FROM MasterDataComplete m ORDER BY m.id DESC", MasterDataComplete.class);
query.setMaxResults(1);
query.setLockMode(LockModeType.PESSIMISTIC_READ);
List<MasterDataComplete> results = query.getResultList();
if (!results.isEmpty()) {
MasterDataComplete singleResult = results.get(0);
id = singleResult.getId() + 1;
}
entity.setId(id);
em.persist(entity);
transaction.commit();
} finally {
if (transaction.isActive()) {
transaction.rollback();
}
}
} finally {
em.close();
}
}
アプリケーションへのいくつかの言葉:
Java スタンドアロンであり、同じ DB サーバーに接続する複数のクライアントで実行され、複数の DB サーバー (Sybase Anywhere、Oracle、Mysql など) で動作する必要があります。
現在、私が残した唯一のアイデアは、ID が既に使用されているときに発生する例外を挿入してキャッチし、再試行することです。列が主キー/一意に設定されていると想定できるため、これは機能します。