使用JPA第二次读取对象不会更新它

时间:2014-07-14 19:18:08

标签: java jpa glassfish eclipselink

我有一个小型的网络应用程序;它的可运行版本减少了。

在每个http请求中,我每次从数据库中读取一个对象 并用它来显示页面的内容。在发布后的第一个请求 Glassfish,一切都很好。但是,如果我更改数据库中的值, 此更改未反映在下一个请求中。

与获取实体相关的代码:

// @WebServlet MyServlet
@Inject
private MyEJB ejb;

// MyServlet.doGet()
MyEntity e = ejb.getResource(1);
System.out.printf("%s: %s%n", e, e.getValue());

// @Stateless MyEJB
@PersistenceContext
private EntityManager em;

// MyEJB.getResource()
TypedQuery<MyEntity> q = em.createNamedQuery("MyEntity.selectById", MyEntity.class);
q.setParameter("id", id);
MyEntity e = q.getSingleResult();
return e;

将请求之间的值更改为asdf!,登录doGet()输出:

Information: pkg.model.MyEntity@7bc0b80e: asdf
Information: pkg.model.MyEntity@5543a940: asdf

显然,实体是在请求之间缓存的,尽管有不同的对象 回。 flush在查询之前或之后getResource实体管理员 没有什么区别,我不明白。 refresh实体确实如此 工作,但不是递归的,并不包括肯定会出现的其他需求 在原始申请中。我尝试其他事情时得到的例外证实EntityManager是JTA管理的,正如我所料。

我正在使用GlassFish Server Open Source Edition 4.0和默认的EclipseLink ORM。

我认为有三种选择可以满足我的需求:

  • 配置,Glassfish控制台或某些WEB-INF / META-INF文件或类似文件
  • 在实际处理每个请求之前我可以执行的一些代码,确保 已缓存的对象与数据库
  • 是最新的
  • 执行此操作的不同注入方式,或将缓存限制为a 按要求提供

我如何实现其中之一,或者实际需要的是不同的东西?


以下完整代码

package pkg.model;

import javax.persistence.Basic;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
import javax.persistence.NamedQueries;
import javax.persistence.NamedQuery;
import javax.persistence.Table;

@Entity
@Table(schema = "MySchema")
@NamedQueries({
    @NamedQuery(name = "MyEntity.selectById",
            query = "SELECT e FROM MyEntity e WHERE e.id = :id")
})
public class MyEntity {
    private Long   id;
    private String value;

    @Id
    @GeneratedValue
    public Long getId() {
        return id;
    }

    @SuppressWarnings("unused")
    private void setId(Long id) {
        this.id = id;
    }

    @Basic
    public String getValue() {
        return value;
    }

    public void setValue(String value) {
        this.value = value;
    }
}

package pkg;

import java.io.IOException;
import javax.ejb.Stateless;
import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;
import javax.persistence.TypedQuery;
import javax.servlet.ServletException;
import pkg.model.MyEntity;

@Stateless
public class MyEJB {
    @PersistenceContext
    private EntityManager em;

    public MyEntity getResource(long id) throws ServletException, IOException {
        TypedQuery<MyEntity> q = em.createNamedQuery("MyEntity.selectById", MyEntity.class);
        q.setParameter("id", id);
        MyEntity e = q.getSingleResult();
        return e;
    }
}

package pkg;

import java.io.IOException;
import java.io.PrintWriter;
import javax.inject.Inject;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import pkg.model.MyEntity;

@WebServlet(name = "MyServlet", urlPatterns = "/")
public class MyServlet extends HttpServlet {
    @Inject
    private MyEJB ejb;

    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        MyEntity e = ejb.getResource(1);
        System.out.printf("%s: %s%n", e, e.getValue());
        resp.setContentType("text/html;charset=UTF-8");
        try (PrintWriter out = resp.getWriter();) {
            out.print(e.getValue());
        }
    }
}

另外,还有一个空的beans.xml和一个vanilla web.xml(只是一个welcome-file-list

1 个答案:

答案 0 :(得分:3)

  

默认情况下,EclipseLink允许共享对象缓存来缓存对象   从数据库中读取以避免重复的数据库访问。如果   数据库直接通过JDBC或其他应用程序更改   或服务器,共享缓存中的对象将是陈旧的。

有不同的选项可以禁用缓存或强制刷新。

可以通过将以下内容添加到persistence.xml

来禁用正常的共享缓存
<property name="eclipselink.cache.shared.default" value="false"/>

使用NamedQueries时,您可能还需要通过添加以下内容来禁用查询缓存:

<property name="eclipselink.query-results-cache" value="false"/>
<property name="eclipselink.refresh" value="true"/>

禁用缓存的另一种更详细的方法是通过查询提示。这可以通过以下方式完成:

TypedQuery<MyEntity> q = em.createNamedQuery("MyEntity.selectById", MyEntity.class);
q.setHint(QueryHints.CACHE_USAGE, CacheUsage.DoNotCheckCache);
// or 
q.setHint("javax.persistence.cache.storeMode", "REFRESH");

在EclipseLink wiki中有很多关于缓存的其他信息:

另见: