我有一个小型的网络应用程序;它的可运行版本减少了。
在每个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。
我认为有三种选择可以满足我的需求:
我如何实现其中之一,或者实际需要的是不同的东西?
以下完整代码
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
)
答案 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中有很多关于缓存的其他信息:
另见: