【发布时间】:2014-12-02 22:48:52
【问题描述】:
我之前遇到过 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() 调用到 @987654326 @/merge() 调用,但没有任何效果。
有人可以帮助我了解不同级别的缓存在这里是如何工作的吗?为什么我新创建的行是“只读的”?
非常感谢。
【问题讨论】:
-
您尚未展示有关如何管理 EntityManager 的代码,但 JPA 中有 2 级缓存。第二个级别是 EMF 级别,而第一个级别是 EntityManager 本身,保留对每个托管对象的引用,以便它可以跟踪更改并保持身份。您可能只保留一个 EM,而不是在完成后释放它 - 它们的目的是根据需要获取,就像您进行交易一样。
-
我正在使用 JTA 进行事务处理,每次创建/编辑/删除都是通过调用
MyClass.getEntityManager().persist()/merge()/remove()进行的,如果我理解这一点,鉴于“远征”是我方法的参数(而且我不知道这个参数是如何获得的),如果this.getEntityManager()不是允许我检索我的“远征”对象的经理,我就不能写this.getEntityManager().refresh(expedition)之类的东西? -
我的观点不是围绕事务处理,而是围绕 EntityManager 生命周期。但我假设如果您使用的是 JTA,那么您可能也会使用容器管理的 EM。当您持久化/合并/查找一个实体时,它会将其加载到当前的 EntityManager 缓存中。该引用在关闭或清除之前不会被释放,如下面的答案中所述。也可以刷新。 em.refresh(expedition) 仅在远征是该 EntityManager 中的托管实体时才有效。如果不是,那么 expedition=em.find(expedition.getId());em.refresh(expedition) 可能会起作用
-
但是你需要看看你的探险队来自哪里。你是怎么读到它的?
-
JTA:UserManaged 还是 ContainerManaged?您如何管理您的交易?
标签: java jakarta-ee caching jpa eclipselink