【问题标题】:Caching in JPA (Eclipselink + Dropwizard + MySQL)JPA 中的缓存(Eclipselink + Dropwizard + MySQL)
【发布时间】:2016-03-18 17:14:58
【问题描述】:

我的查询返回过时的数据库数据时遇到问题,因此我认为它与缓存有关。我完全不明白发生了什么,我很想知道。

我有一个映射到实体的数据库表应用程序:

@Entity
@Table(name = "app_application", catalog = "something", schema = "")
@XmlRootElement
@NamedQueries({
  @NamedQuery(name = "Application.findById", 
    query = "SELECT a FROM Application a WHERE a.id = :id"))
  }
)
public class Application implements Serializable {

  private static final long serialVersionUID = 1L;
  @Id
  @GeneratedValue(strategy = GenerationType.IDENTITY)
  @Basic(optional = false)
  @Column(name = "id")
  private Integer id;

  ...

  @JoinColumn(name = "status", referencedColumnName = "id")
  @ManyToOne(optional = false)
  private ApplicationStatus status;

  ....

我还在 Dropwizard 中实现了一个 REST 服务,我可以在其中获取这些野兽:

@GET
@Timed
@Path("/{id}")
public Application findById(@PathParam("id") int id) {
  return em.find(Application.class, id); // em is an entity manager
}

如果我启动 Dropwizard 应用程序并访问此资源,我的应用程序将第一次正确返回。然后,如果我转到数据库并手动将应用程序状态值从“接受”更改为“拒绝”(外键),并再次访问我的 REST 服务以获取相同的应用程序,它不会更新状态属性(我的手动数据库更改被忽略)。如果我关闭整个系统并重新启动,REST 服务会获取更新后的值并正确返回实体(直到我再次手动修改数据库)。

这是我的持久化单元:

<?xml version="1.0" encoding="UTF-8"?>
<persistence version="2.1" xmlns="http://xmlns.jcp.org/xml/ns/persistence" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/persistence http://xmlns.jcp.org/xml/ns/persistence/persistence_2_1.xsd">
<persistence-unit name="to.rented_RentedToPMS_jar_1.0-SNAPSHOTPU" transaction-type="RESOURCE_LOCAL">
<provider>org.eclipse.persistence.jpa.PersistenceProvider</provider>
<class>pms.core.entities.applications.Application</class>
<class>pms.core.entities.applications.ApplicationStatus</class>
<properties>
  <property name="javax.persistence.jdbc.url" value="jdbc:mysql://localhost:3306/rented?zeroDateTimeBehavior=convertToNull"/>
  <property name="javax.persistence.jdbc.user" value="someuser"/>
  <property name="javax.persistence.jdbc.driver" value="com.mysql.jdbc.Driver"/>
  <property name="javax.persistence.jdbc.password" value="somepassword"/>
</properties>
</persistence-unit>
</persistence>

没有任何结果,我尝试添加:

  <property name="eclipselink.query-results-cache" value="false"/>
  <property name="eclipselink.cache.shared.default" value="false"/>

以及使用带有提示的 NameQuery 进行获取:

setHint(QueryHints.CACHE_USAGE, CacheUsage.DoNotCheckCache)

谁能帮我解释一下是怎么回事?

编辑:

这似乎解决了这个问题。但是,这是否意味着我需要为每个实体调用刷新?如果我想获取所有应用程序怎么办?我是否需要遍历所有这些并刷新?这对我来说似乎很愚蠢,所以我想答案是否定的......

@GET
@Timed
@Path("/noauth/{id}")
public Application findById(@PathParam("id") int id)  { 
    Application a = em.find(Application.class, id);
    em.refresh(a);
    return a;
}

【问题讨论】:

    标签: java jpa caching eclipselink dropwizard


    【解决方案1】:

    1) 尝试添加到持久化单元(更多信息见this):

      <shared-cache-mode>ENABLE_SELECTIVE</shared-cache-mode>
    

    2)如果(2)不行,尝试在Entity前加注解@Cacheable(false):

    ...
    @Cacheable(false)
    public class Application implements Serializable {
    

    3) 如果 (3) 不起作用,请将应用程序运行到调试模式并在 em.find(Application.class, id) 中设置断点或在此行中添加日志记录,如果您的应用程序仅第一次在断点处停止,休息的问题,如果每次都停止 - 使用 JPA。

    更新:如果 em.refresh(a) 对您有帮助,则意味着您的 EntityManager 在您的 servlet 中不是无状态的,例如它是无状态的示例:

     @Stateless 
     public class YourServlet {
        @PersistenceContext EntityManager em;
    
        public void enterOrder(int custID, Order newOrder) {
          Application a = em.find(Application.class, id);
          ...
        }
    

    这是有状态的:

     @Stateful
     public class YourServlet {
        @PersistenceContext EntityManager em;
    
        public void enterOrder(int custID, Order newOrder) {
          Application a = em.find(Application.class, id);
          ...
        }
    

    【讨论】:

    • (1) 没有帮助,(2) 没有帮助,(1) 和 (2) 的组合没有帮助。我在 em.find() 前后添加了日志记录语句。每次我访问 REST 时都会打印出来,所以它应该是 JPA。
    • 我修复了我的帖子,它看起来像在您的 servlet EntityManager 中是有状态的,并且可以处理一个事务。您可以尝试为每个请求更改 em 无状态或打开新事务
    • 嗯,可能是无状态问题,但说实话,我真的不知道如何解决它。我不确定如何将 dropwizard 资源转换为无状态的——我不清楚 @Stateless 注释在 Dropwizard 架构中的位置:Dropwizard 是在 Jersey 上构建的。资源在应用程序启动时注册到 Jersey。这也是我创建实体管理器的地方——我将它作为主应用程序类的静态属性,并使用资源类中的静态 getter 检索它。这种方法绝对错误吗?
    • 在某些时候调用 em.clear(),因为这实际上与获取新的 EntityManager 相同。关闭共享缓存后,所有查询都需要在调用 clear 后从数据库中获取数据,从而恢复正常的 EntityManager 使用和缓存。
    猜你喜欢
    • 2011-03-29
    • 2014-01-22
    • 2012-11-17
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多