我之前遇到过 JPA 问题。 我有两个应用程序:第一个使用 Java/JPA (EclipseLink),第二个使用 PHP。这两个应用程序可以访问同一个数据库。 现在,我通过 Java 访问“Expedition”对象,然后通过 Web 服务调用 PHP 应用程序(应该修改共享数据库表“Expedition”中该对象的属性),然后通过访问该属性Java 应用程序。
问题是,对象似乎没有在 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;
信息远征:
@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()
调用,但没有任何效果。
有人可以帮助我了解不同级别的缓存在这里是如何工作的吗?为什么我新创建的行是“只读”的?
非常感谢。
最佳答案
您正在使用的设置试图绕过缓存。 ("eclipselink.read-only", "true") 使其绕过一级缓存,而 ("eclipselink.cache-usage", "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
关于java - JPA缓存如何刷新外部修改的实体?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/26254142/