【问题标题】:Spring / Eclipselink / MySQL application data issueSpring / Eclipselink / MySQL 应用程序数据问题
【发布时间】:2011-12-27 14:56:54
【问题描述】:

我的应用程序遇到了一个奇怪的问题。我已经实现了优惠券评级功能。根据应用程序,我必须搜索一张优惠券,然后单击它会显示一个描述页面,那里有一个评级选项,用于为用户进行首选评级。我正在测试的是以下场景:我搜索优惠券“测试”,点击它进入描述页面,并对其进行评分,并检查它是否反映在DB中。最新的评分值和总评分将反映在描述页面中。然后我再次回到主页,搜索同一张优惠券,点击它进入它的描述页面并再次评分。发生的情况是,数据库正确更新了 4-6 次,之后当我搜索该优惠券并转到描述页面时,它显示了以前的评级值和总评级值,这可能是它被评级几次时的值以前(此值已在 db 中被覆盖)。然后,如果我对其进行评分,则数据库中的值不会更新。从那里开始,这个功能就会中断。我尝试了几个选项,禁用缓存,设置一些命中 eclipselink 等,但没有解决问题。请分享您的建议。我的代码中的一些重要部分:

Persistence.xml:

<shared-cache-mode>NONE</shared-cache-mode>
<property name="eclipselink.cache.shared.default" value="false"/>
<property name="eclipselink.query-results-cache" value="false"/>  

Coupon 和 CouponRating 具有单向的一对一映射:(之前我使用双向映射,然后也出现了同样的问题。)

在 CouponRating.java 中:

@Cacheable(false)
@Entity
@Table(name = "Coupon_Rating")
public class CouponsRatings {
....
....
....
@OneToOne
@JoinColumn(name="coupon_id", unique=true, nullable=false, updatable=false)
private Coupon coupon;

@Version
@Column(name="version")
private long version;

@Column(name="uuid") 
private String uuid;
....
....
....

@Override
public int hashCode() {
    int hash = 3;
    hash = 89 * hash + (this.uuid != null ? this.uuid.hashCode() : 0);
    hash = 89 * hash + Long.valueOf(this.version).intValue();
    return hash;
}

    @Override
public boolean equals(Object obj) {
  if((obj == null) || (this.getClass() != obj.getClass()))
        return false;

  CouponsRatings couponsRatings = (CouponsRatings)obj;
  return (this.version == couponsRatings.getVersion() &&
    this.uuid.equalsIgnoreCase(couponsRatings.getUuid()));
}
....
....

RatingManagerImpl.java

....
....

@Transactional
public CouponsRatings saveRating(CouponsRatings rating) throws AppException{
    return ratingDAO.saveRating(rating);
}

@Transactional
public CouponsRatings updateRating(CouponsRatings rating)
        throws AppException {
    return ratingDAO.updateRating(rating);
}

public CouponsRatings findRatingById(Long id) {
    return ratingDAO.findRatingById(id);
}

public CouponsRatings refreshObject(CouponsRatings rating) {
    return ratingDAO.refreshObject(rating);
}

....
....

在 RatingDao 中:

....
....
private EntityManager entityManager;

@PersistenceContext
public void setEntityManager(EntityManager entityManager) {
this.entityManager = entityManager;
}

@Override
public CouponsRatings saveRating(CouponsRatings rating) throws AppException {
try {
       entityManager.persist(rating);
} catch (Exception e) {
   logger.debug("Error in saving coupon. Reason: " + e.getMessage());
   throw new CouponzleAppException(e.getMessage());
}
return rating;
}

@Override
public CouponsRatings findRatingByCouponId(Long id) {
  CouponsRatings couponsRatings = null;
  try {
    couponsRatings = (CouponsRatings) entityManager
            .createNamedQuery("findRatingByCouponId")
            .setHint(QueryHints.CACHE_USAGE, 
                             CacheUsage.DoNotCheckCache)
            .setParameter(1, id).getSingleResult();
       } catch (NoResultException exception) {
        logger.error("No active couponsRatings available for coupon id : "
                    + id);
       }
    return couponsRatings;
}

@Override
public CouponsRatings updateRating(CouponsRatings rating)
        throws AppException {
    CouponsRatings updatedRating = null;
    try {
        updatedRating = entityManager.merge(rating);
    } catch (Exception e) {
        logger.debug("Error in updating coupon. Reason: " + .getMessage());
        throw new AppException(e.getMessage());
    }
    return updatedRating;
}

@Override
public CouponsRatings refreshObject(CouponsRatings rating) {
    CouponsRatings updatedRating = null;
    updatedRating = entityManager.merge(rating);
    entityManager.refresh(updatedRating);
    return rating;
    }

来自 Action 类:(仅检索和更新场景)

// this sometimes loads old date as i have described
couponsRating = ratingsManager.findRatingByCouponId(Long.valueOf(
                couponId).longValue());

cupnsRating.setCurrentRating(currentRating);
cupnsRating.setLastRatingDate(new Date());
cupnsRating.setRatingSum(ratingSum);
cupnsRating.setTotalRatings(totalRatings);
couponsRating = ratingsManager.updateRating(cupnsRating);
// I tried to refresh updated object after i get the issue, but still no luck:
// couponsRating = ratingsManager.refreshObject(couponsRating);

如果我做错了什么,请告诉我。谢谢。

【问题讨论】:

  • 您的 refreshObject 正在返回传递给方法的未刷新评级,而不是刷新后的版本。这可能就是为什么即使在刷新后也没有进行更改的原因。此外,虽然它看起来比获取主键和调用 find 更简单,但方法中的 Merge 增加了确定更改和不必要地合并它们的开销。

标签: java mysql spring transactions eclipselink


【解决方案1】:

检查 ratingManager 是如何存储和重用的。我的猜测是有多个实例,每个实例都存储自己的 EntityManager 实例。 EntityManager 有一个缓存,类似于事务,因此它不会看到在其他 EntityManager 范围内所做的更改,除非它的实体副本被刷新。

如果是这种情况,您可以尝试调用 refresh(在修复您的 refreshObject 方法以返回刷新的对象然后重新应用更改之后),或在适当的时间从 EntityManager 中逐出/清除实体,以便从重新加载实体数据库。

【讨论】:

    猜你喜欢
    • 2020-11-26
    • 1970-01-01
    • 1970-01-01
    • 2021-01-07
    • 1970-01-01
    • 1970-01-01
    • 2021-08-31
    • 2019-07-25
    • 1970-01-01
    相关资源
    最近更新 更多