1

这篇文章是关于 JPA 的持久性问题。使用的 JPA 提供程序是 weblogic 12c 提供的 Oracle Toplink,使用 EclipseLink 构建。

用户进行“n”次交互/事务,应用程序将每个事务写入数据库。在重负载下,在编写事务时,应用程序面临重复键异常。

第一个事务已成功写入数据库,但后续事务有时会因重复键异常而被拒绝。

正如我所说,该应用程序使用 JPA 2.0,其中默认启用共享缓存,我认为这与共享缓存有关。

我这样说是因为同一个应用程序在使用 JPA 1.0 的 Weblogic 10 中运行良好,并且其中没有共享缓存的概念。

现在回到这个问题,参与插入事务的每个实体都由一个嵌入的主键类唯一标识,该类具有覆盖的 hashcode/equals()(请参见下面的类定义)。

@EmbeddedId
private CallerEntityPK pk;

//@Column attributes    

}

@Embeddable
public class CallerEntityPK implements Serializable {

    @Column(name="SESSION_ID")
    private String sessionId;   //FIRST_USER_SESSION,SECOND_USER_SESSION

    @Column(name="TRANSACTION_NBR")
    private String transNo;     //01 , 02 etc... 

    //Getter setters

    @Override
    public boolean equals(Object o) {
        if (o == this) {
            return true;
        }
        if ( ! (o instanceof CallerEntity )) {
            return false;
        }
        CallerEntity other = (CallerEntity ) o;
        return this.sessionId.equals(other.sessionId)
            && this.transNo.equals(other.transNo;);
    }

    @Override
    public int hashCode() {
        final int prime = 31;
        int hash = 17;
        hash = hash * prime + this.sessionId.hashCode();
        hash = hash * prime + this.transNo.hashCode();
        return hash;
    }
}

主键是 sessionid(FIRST_USER_SESSION) 和事务号的组合(01 表示第一次插入,02 表示第二次插入 ....)例如:FIRST_USER_SESSION 和 01

第一个交易包:FIRST_USER_SESSION01 第二个交易包:FIRST_USER_SESSION02

  1. 在写入第一个插入事务(带有 pk FIRST_USER_SESSION 01 的实体)之前,它检查了 L2 缓存,并且由于它不在缓存中,它成功地持久化到 DB。

  2. 写入第一个事务后,它在 L2 缓存中更新。(具有 FIRST_USER_SESSION 01 键的实体被缓存)

  3. 现在对于第二个插入事务(键为 FIRST_USER_SESSION 02 的实体),在持久化之前检查 L2 缓存,我猜测第二个事务的实体被认为与 L2 缓存中已经存在的实体相同。即使 pk 不同(FIRST_USER_SESSION02),我认为框架将其识别为重复对象。(基于 equals() 和 hashcode() 覆盖)

结果,尝试插入相同的重复对象并引发重复键异常。

问题1)我的理解正确吗?我问这个的原因是每个实体都有唯一的密钥,这仅在高容量时发生。可能是其他一些事务(实体)返回相同的哈希码并使对象相同。

问题 2)如果是这种情况,我可以让实体使用隔离缓存并始终刷新并立即过期(如下面的代码所示)。
我只想禁用此实体的缓存,请让我知道您的意见

@Entity 
@Table(name="T_CALLER_TRANS") 
@Cache(isolation=CacheIsolationType.ISOLATED, expiry=0, alwaysRefresh=true)
public class CallerEntity implements Serializable {

}

问题 3) 进行此更改后,我需要对应用程序进行负载测试。应用程序的用户通过 MQ 和 HTTP 进行交互。我需要将足够的消息放入 MQ

4

0 回答 0