JPA缓存如何刷新外部修改的实体?

时间:2014-10-08 09:59:17

标签: java java-ee caching jpa eclipselink

我早些时候遇到过JPA问题。 我有两个应用程序:主要使用Java / JPA(EclipseLink),第二个使用PHP。这两个应用程序可以访问同一个数据库。 现在,我正在访问" Expedition"对象通过Java,然后通过Web服务调用PHP应用程序(它应该在共享数据库表中修改此对象的属性" Expedition"),然后通过Java应用程序访问该属性。 / p>

问题是,即使在数据库中修改了对象,该对象似乎也不会在Java应用程序中进行修改。我正在考虑缓存问题。

原始代码(简化):

System.out.println(expedition.getInfosexpedition()); // null

// Calling the web-service (modification of the "expedition" object in the database)
this.ec.eXtractor(expedition);

System.out.println(expedition.getInfosexpedition()); // Still null, should not be

" Expedition"的定义和" Infosexpedition"课程:

探险:

@Entity
@Table(name = "expedition")
@XmlRootElement
public class Expedition implements Serializable {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    @Basic(optional = false)
    @Column(name = "idExpedition")
    private Integer idExpedition;
    @OneToOne(cascade = CascadeType.ALL, mappedBy = "idExpedition")
    @XmlTransient
    private Infosexpedition infosexpedition;

Infosexpedition:

@Entity
@Table(name = "infosexpedition")
@XmlRootElement
public class Infosexpedition implements Serializable {
    private static final long serialVersionUID = 1L;
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    @Basic(optional = false)
    @Column(name = "idInfoExpedition")
    private Integer idInfoExpedition;
    @JoinColumn(name = "idExpedition", referencedColumnName = "idExpedition")
    @OneToOne(optional = false)
    @XmlTransient
    private Expedition idExpedition;

我已经能够通过这样做来使原始代码工作:

System.out.println(expedition.getInfosexpedition()); // null

// Calling the web-service (modification of the "expedition" object in the database)
this.ec.eXtractor(expedition);

try
{
    // Getting explicitly the "infosExpedition" item through a simple named request
    Infosexpedition infos = this.ec.getFacade().getEm().createNamedQuery("Infosexpedition.findByIdExpedition", Infosexpedition.class)
           .setParameter("idExpedition", expedition)
           .setHint("eclipselink.refresh", "true")
           .setHint("eclipselink.cache-usage", "DoNotCheckCache")
           .setHint("eclipselink.read-only", "true") // This line did the trick
           .getSingleResult();
     expedition.setInfosexpedition(infos);
}
catch (NoResultException nre) {}

System.out.println(expedition.getInfosexpedition()); // Not null anymore, OK

我试图了解这里发生了什么,为什么我必须指定一个"只读"提示这项工作...在此之前,我尝试了几乎所有内容,从evictAll()来电到detach() / merge()来电,没有任何效果。

有人可以帮我理解不同级别的缓存如何在这里工作吗?为什么我新创建的行"只读" ?

非常感谢。

2 个答案:

答案 0 :(得分:2)

您正在使用的设置正在尝试绕过缓存。 (" eclipselink.read-only"," true")使其绕过第一级缓存,而(" eclipselink.cache-usage",&# 34; DoNotCheckCache")使查询转到数据库,而不是从二级缓存中提取数据。最后(" eclipselink.refresh"," true")刷新共享缓存中的数据,而不是返回预构建的对象。即使您已对请求之间的对象进行了更改,您的外观也必须对两个请求使用相同的EntityManager。正如评论中所提到的,EntityManager旨在用作事务,因此您可以与事务期间所做的更改隔离开来。如果这对您不起作用,则应在第一次调用后清除或释放entityManager,以便可以拾取Web服务修改后的调用。

如果此应用程序之外的应用程序将频繁更改数据,您可能希望查看禁用共享缓存,如下所述: https://wiki.eclipse.org/EclipseLink/FAQ/How_to_disable_the_shared_cache%3F

并且还实现乐观锁定以防止应用程序使用陈旧数据覆盖另一个应用程序,如下所述: https://wiki.eclipse.org/EclipseLink/UserGuide/JPA/Basic_JPA_Development/Mapping/Locking/Optimistic_Locking

答案 1 :(得分:1)

你称之为缓存的是第一级缓存,在时间t为数据库状态的内存投影。

此“缓存”具有与实体管理器本身相同的生命周期,并且通常不会刷新,直到您明确地清除它(使用myEntityManager.clear())(您不应该)或强制它重新生成特定实体实例(使用myEntityManager.refresh(myEntityInstance),这是你应该去的方式)

有关更详细的说明,请参阅Struggling to understand EntityManager proper useJpa entity lifecycle