3

アプリケーションにHibernateを使用しています。hibernateが重複IDを生成することがあり、私が使用した戦略は、テーブルからmax(ID)を実行して1を追加するincrementです。なぜそれが発生するのかわかりません。突然発生し、その後、そのテーブル挿入操作に対する後続のすべての要求が失敗します。この回避策は、tomactサーバーを再起動することです。

こちらが申し込みの詳細です

1. liferay-tomcat.eachにデプロイされた3つのアプリケーションには、独自のabstraction-impls.jarがあります。このJARには、Hibernateを使用してOracleと対話するためのクラスが含まれています。これがこの問題を引き起こす可能性のある1つのケースであると思われます。

2.3つのアプリケーションすべてに休止状態に関連するJARがあります

マルチスレッドが原因で問題が発生するかどうかを確認するために、次のテストを行いました 。1) 3つのスレッドを作成しました。各スレッドはforループを20回実行して、同じテーブルに挿入します>これで問題は見つかりませんでした。全てが上手く行きました。

上記のサンプルコードは次のとおりです。

public class ThreadTest implements Runnable{
@Override
public void run() {
    // TODO Auto-generated method stub
    for(int i=0;i<20;i++){
        UserManagement userManagement = new UserManagementImpl(-1);
        Context context = new Context();
        context.setUserId("testUser");
        context.getUserContextMap().put("password", "shiva123");
        try{
        int sessionId = userManagement.login(context);
        System.out.println("thread<<"+Thread.currentThread().getName() + ">>    "+sessionId);
        }catch(Exception e){
            e.printStackTrace();
        }

    }
}

public static void main(String[] args) {
    Thread t1 = new Thread(new ThreadTest());
    Thread t2 = new Thread(new ThreadTest());
    Thread t3 = new Thread(new ThreadTest());
    t1.setName("t1");
    t2.setName("t2");
    t3.setName("t3");
    t1.start();
    t2.start();
    t3.start();
}

}

正しいIDを取得する方法は問題ですか、それとも重複IDの生成を回避する方法ですか?

これが私に問題を与えているコードです。

以下は、Hibernateマッピングクラスです。

import javax.persistence.Column;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.SequenceGenerator;
import javax.persistence.Table;
import javax.persistence.UniqueConstraint;



@javax.persistence.Entity
@Table(name="entities",
uniqueConstraints = {@UniqueConstraint(columnNames={"id"})})
@org.hibernate.annotations.GenericGenerator(
    name = "test-increment-strategy",
    strategy = "increment")
public class EntityImpl extends Entity {

/**
 * Serial Version UID for this class
 */
private static final long serialVersionUID = -9214466697134157251L;
@Override
public String toString() {
    return "EntityImpl [entityId=" + entityId + ", entityName="
            + entityName + ", entityType=" + entityType
            + ", parentEntityId=" + parentEntityId + ", entityHierarchy="
            + entityHierarchy + "]";
}



private int entityId;
private String entityName;
private String entityType;
private int parentEntityId;
private String entityHierarchy;


@Id
    @GeneratedValue(generator = "test-increment-strategy")
@Column(name = "ID", nullable = false, updatable = false)
public int getEntityId() {
    return entityId;
}
/** Sets the Entity ID for this instance */
public void setEntityId(int entityId) {
    this.entityId = entityId;
}
/** Retrieves the name of this Entity instance */
@Column(name = "entity_name", nullable = false)
public String getEntityName() {
    return entityName;
}
/** Sets the name of this Entity instance */
public void setEntityName(String entityName) {
    this.entityName = entityName;
}
/** Retrieves the type of this Entity instance */
@Column(name = "entity_type", nullable = false, updatable = false)
public String getEntityType() {
    return entityType;
}
/** Sets the type of this Entity instance */
public void setEntityType(String entityType) {
    this.entityType = entityType;
}
/** Retrieves the Parent Entity ID for this instance */
@Column(name = "parent_id")
public int getParentEntityId() {
    return parentEntityId;
}
/** Sets the Parent Entity ID for this instance */
public void setParentEntityId(int parentEntityId) {
    this.parentEntityId = parentEntityId;
}

@Column(name = "ENTITY_HIERARCHY", nullable = false, updatable = false)
public String getEntityHierarchy() {
    return entityHierarchy;
}


public void setEntityHierarchy(String entityHierarchy) {
    this.entityHierarchy = entityHierarchy;
}

}

以下はエンティティを保存する方法です

private boolean save (Serializable object, Session session) throws EntityNotFoundException, InternalSystemException {
    logger.debug("save() - start"); 
    Transaction tx = null;
    boolean successful = false;
    boolean localInit = false;
    try {
        if (session == null) {
            session = createSession();
            tx = session.beginTransaction();
            //session.save(object);
            localInit = true;
        }
        session.save(object);
        logger.debug("**********************************");
        logger.debug("object: "+object);
        logger.debug("**********************************");
        if (localInit == true) {
            tx.commit();
        }
        successful = true;
    } catch(HibernateException ex) {
        logger.error("error in saving entity "+ ex);
        if (localInit == true && tx !=null)
            tx.rollback();
        ex.printStackTrace();
        throw new InternalSystemException("error in saving entity "+ ex);
    } catch(Exception ex) {
        logger.error("error in saving entity "+ex);
        if (localInit == true && tx !=null)
            tx.rollback();
        new InternalSystemException("error in saving entity "+ ex);
    }finally {
        if (localInit && session != null) {
            session.flush();
            session.clear();
            session.close();
        }
    }
    if (logger.isDebugEnabled()) {
        logger.debug("save() - end"); 
    }
    return successful;
}

エラーが常に発生するわけではありませんが、発生すると同じことが継続され、テストされるOracle環境はOracleRACKです。

4

1 に答える 1

1

このような状況では、インクリメント戦略を使用しないでください。メモリ内のカウンターに最大値をロードし、新しい ID が要求されるたびに値を増やします。3 つのアプリケーションがデプロイされているため、3 つのカウンターがあり、それぞれが同じ初期値に初期化されているため、同じ ID が返されます。

これは明らかに文書化されています:

インクリメント

他のプロセスが同じテーブルにデータを挿入していない場合にのみ一意である long、short、または int 型の識別子を生成します。クラスタで使用しないでください

(強調は私のものではありません)

シーケンス ジェネレーターでは、同じ問題は発生しません。存在する場合は、構成に何かが欠けているか、3 つのアプリのいずれかが引き続きインクリメント戦略を使用しているか、外部から ID を挿入しているか、データベース内のシーケンスの初期値が間違っています。コード、ID の最大値、およびシーケンスの定義を見ないと、なんとも言えません。

于 2012-12-25T08:08:08.433 に答える