hibernate - hibernate session 中的持久数据变得陈旧,有时 hibernate 会生成重复的 ID

标签 hibernate session tomcat liferay

我正在为我的应用程序使用 hibernate 。有时 hibernate 会生成重复的 ID,我使用的策略是增量,它从表中执行 max(ID) 并添加一个。我不知道它为什么会发生,它突然发生,之后对该表插入操作的所有后续请求都失败了。解决方法是重新启动 tomact 服务器。

申请详情

1. 部署在 liferay-tomcat 上的 3 个应用程序。每个应用程序都有自己的 abstraction-impls.jar。此 JAR 包含使用 Hibernate 与 oracle 交互的类。我怀疑这是导致此问题的一种可能情况。

2.所有 3 个应用程序都有 hibernate 相关的 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。

最佳答案

在这种情况下不应使用增量策略。它包括将最大值加载到内存中的计数器中,然后在每次请求新 ID 时递增它。由于您部署了 3 个应用程序,因此您有 3 个这样的计数器,每个都初始化为相同的初始值,因此它们将返回相同的 ID。

这显然是documented :

increment

generates identifiers of type long, short or int that are unique only when no other process is inserting data into the same table. Do not use in a cluster.

(重点不是我的)

序列生成器不会出现同样的问题。如果是这样,那么要么是你在配置中遗漏了某些东西,要么是三个应用程序之一继续使用增量策略,要么是你从外部插入 ID,要么是数据库中序列的初始值是错误的。没有看到代码,ID的最大值,序列的定义,不好说。

关于hibernate - hibernate session 中的持久数据变得陈旧,有时 hibernate 会生成重复的 ID,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/14021112/

相关文章:

apache - Tomcat 重定向将用户带到域外

java - catalina.out 每日滚动

hibernate - 限制不同查询返回的结果

mysql - JPA Hibernate - 多种数据库方言和 nvarchar(length) 数据类型

node.js - 使用 JWT 管理多个设备 Node js 的用户 session

java - jdbc、tomcat、apache 和 mod-jk 错误 "No suitable driver"

用于命名查询删除操作的 hibernate 实体监听器

spring - 使用 PostGIS Geometry Hibernate 持续失败

javascript - $.couch.session 返回空名称的 userctx

跨同一域的子页面的 PHP session