有 Java 编程相关的问题?

你可以在下面搜索框中键入要查询的问题!

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

我有一个小的web应用程序;下面是它的简化可运行版本

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

与获取实体相关的代码:

// @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服务器开源版本4.0和默认的EclipseLink ORM

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

  • 配置,位于Glassfish控制台或某些WEB-INF/META-INF文件或类似文件中
  • 我可以在实际处理每个请求之前执行一些代码,确保 已缓存的对象是数据库的最新对象
  • 一种不同的注入方式,可以实现这一点,也可以将缓存限制为 按请求计算

我如何才能实现其中的一个,或者它是我真正需要的不同的东西


完整代码如下

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());
        }
    }
}

另外,一个空的豆子。xml和普通web。xml(只是一个welcome-file-list


共 (1) 个答案

  1. # 1 楼答案

    By default EclipseLink enables a shared object cache to cache objects read from the database to avoid repeated database access. If the database is changed directly through JDBC, or by another application or server, the objects in the shared cache will be stale.

    有不同的选项来禁用缓存或强制刷新

    通过将以下内容添加到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中有很多关于缓存的附加信息:

    另请参见: