2

レガシ コードの問題により、一意のインデックスを手動で計算する必要があり、データベースに新しい行を挿入するときに 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 が既に使用されているときに発生する例外を挿入してキャッチし、再試行することです。列が主キー/一意に設定されていると想定できるため、これは機能します。

4

1 に答える 1

0

問題は、PESSIMISTIC_READを使用すると、最も高い ID を持つ行で他のUPDATEをブロックしていることです。他のSELECTをブロックしたい場合は、 PESSIMISTIC_WRITEを使用する必要があります。

その行をUPDATEするつもりはないので、奇妙に思えることはわかっています...しかし、SELECTの実行中に他のブロックが必要な場合は、嘘をついて言う必要があります。 it".. ..その行を読み取ることが許可されないように、DB エンジンはコミット前に変更すると判断します。

ドキュメントによると、SERIALIZABLE自体は、すべてのプレーンな SELECT ステートメントを SELECT ... LOCK IN SHARE MODE に変換するため、すでに明示的に行っていること以上のことはしません。

于 2013-09-14T22:45:24.637 に答える