2012-12-24 85 views
3

我正在爲我的應用程序使用Hibernate。有時侯hibernate會生成重複的ID,我使用的策略是增量,它會從表中增加一個max(ID)。我不知道爲什麼會發生這種情況,並且突然發生,並且之後對該表插入操作的所有後續請求都失敗。解決方法是重新啓動tomact服務器。休眠會話中的持久數據變得過時,有時會通過休眠生成重複ID

這裏有應用

3應用程序部署在Liferay的-tomcat.each細節都有自己的抽象impls.jar.This JAR中包含用於使用Hibernate oracle的交互。我可以懷疑這是導致這個問題的一個可能的情況。

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環境是Oracle RACK。

+2

你有3個不同的webapps,每個webapps使用增量策略插入到相同的表中嗎? –

+0

是的.. **有3個Web應用程序和相同的JAR,並且每個插入到同一個Tablse中都被複制到每個Web應用程序的lib文件夾**。他們使用增量策略。即使我也嘗試使用序列。但問題仍然存在。 –

回答

1

在這種情況下不應該使用增量策略。它包括將最大值加載到內存中的計數器中,然後在每次詢問新的ID時遞增。由於您部署了3個應用程序,因此您有3個此類計數器,每個計數器初始化爲相同的初始值,因此它們將返回相同的ID。

這顯然是documented

增量

生成特有隻有當沒有其它進程在插入數據到相同的表型長,短或INT的標識符。 做 不用於集羣

(重點不是我的)

序列發生器會不會出現同樣的問題。如果確實如此,那麼要麼是在配置中丟失了某些內容,要麼是三個應用程序中的一個繼續使用增量策略,或者從外部插入ID,或者序列在數據庫中的初始值是錯誤的。沒有看到代碼,ID的最大值以及序列的定義,很難說。