这篇文章是关于 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
在写入第一个插入事务(带有 pk FIRST_USER_SESSION 01 的实体)之前,它检查了 L2 缓存,并且由于它不在缓存中,它成功地持久化到 DB。
写入第一个事务后,它在 L2 缓存中更新。(具有 FIRST_USER_SESSION 01 键的实体被缓存)
现在对于第二个插入事务(键为 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