JPA + Hibernate + EHCache,出乎意料的行为 [英] JPA + Hibernate + EHCache, unexpected behavior

查看:74
本文介绍了JPA + Hibernate + EHCache,出乎意料的行为的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我试图在我的工作原型中实现EHCache,我的javax.persistence.Entity 表示我的数据库(MySQL,mysql-connector-java-5.1.20)上的表。 jar),它以XML的形式提供给消费者。



我遇到的问题是,看起来Hibernate仍然从数据库中检索数据, EHCache将查询结果存储在内存中。



我使用 EHCache监视器查看内存中的项目数,并在缓存过期之前直接在数据库上更改数据,以确定是否实际使用了缓存数据。



我一直在寻找这个问题的复制而没有成功,所以也许我错过了一些东西(我只是在java世界中开发)。



我的档案



pom.xml

 <依赖性> 
< groupId> org.hibernate< / groupId>
< artifactId> hibernate-validator< / artifactId>
< version> 4.3.0.Final< / version>
< /依赖关系>
< dependency>
< groupId> org.hibernate< / groupId>
< artifactId> hibernate-entitymanager< / artifactId>
< version> 4.1.4.Final< / version>
< /依赖关系>
< dependency>
< groupId> org.hibernate< / groupId>
< artifactId> hibernate-ehcache< / artifactId>
< version> 4.1.4.Final< / version>
< /依赖关系>
< dependency>
< groupId> net.sf.ehcache< / groupId>
< artifactId> ehcache-core< / artifactId>
< version> 2.5.2< / version>
< /依赖关系>
< dependency>
< groupId> org.terracotta< / groupId>
< artifactId> ehcache-probe< / artifactId>
< version> 1.0.2< / version>
< /依赖关系>

实体班

  package myPrototype.entities 

import javax.persistence.Cacheable;
import javax.persistence.Entity;
import javax.persistence.NamedQueries;
import javax.persistence.NamedQuery;
import javax.persistence.Table;
import javax.xml.bind.annotation.XmlRootElement;
import org.hibernate.annotations.Cache;
import org.hibernate.annotations.CacheConcurrencyStrategy;

@Entity @Cacheable
@Cache(usage = CacheConcurrencyStrategy.READ_ONLY)
@Table(name =Cars)
@XmlRootElement
@NamedQueries ({
@NamedQuery(name =Cars.findAll,query =SELECT d FROM Cars d),
[...]
public class Cars实现Serializable {
private static final serialVersionUID = 1L;
@Basic(optional = false)
@NotNull
@Column(name =id)
@ReferenceField
private int id;
[...]

ehcache.xml

 <?xml version =1.0encoding =UTF-8?> 
< ehcache>
< cache name =myPrototype.entities.Cars
maxElementsInMemory =500
eternal =false
overflowToDisk =false
timeToIdleSeconds =60
timeToLiveSeconds =120/>
< / ehcache>

* 我尝试设置永恒=真,但结果仍然相同
$ b persistence.xml

 <?xml version =1.0encoding =UTF-8?> 
< persistence version =2.0xmlns =http://java.sun.com/xml/ns/persistencexmlns:xsi =http://www.w3.org/2001/XMLSchema-实例xsi:schemaLocation =http://java.sun.com/xml/ns/persistence http://java.sun.com/xml/ns/persistence/persistence_2_0.xsd\">
< persistence-unit name =MyPrototypetransaction-type =JTA>
< provider> org.hibernate.ejb.HibernatePersistence< / provider>
< jta-data-source> java:app / jdbc / mysqlserver / prototype< / jta-data-source>
< exclude-unlisted-classes> false< / exclude-unlisted-classes>
< shared-cache-mode> ENABLE_SELECTIVE< / shared-cache-mode>
<属性>
<! - property name =hibernate.cache.region.factory_classvalue =org.hibernate.cache.ehcache.SingletonEhCacheRegionFactory/ - >
< property name =hibernate.cache.region.factory_classvalue =org.hibernate.cache.ehcache.EhCacheRegionFactory/>
< property name =hibernate.cache.use_second_level_cachevalue =true/>
< property name =hibernate.cache.use_query_cachevalue =true/>
< property name =hibernate.cache.region_prefixvalue =/>
< / properties>
< / persistence-unit>
< /余辉>

* 我尝试在SingletonEhCacheRegionFactory和EhCacheRegionFactory之间切换
$ b

EJB

  import myPrototype.entities.Cars 
import java.util.Date;
import java.util.List;
import javax.ejb.Stateless;
import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;

@Stateless
public class CarsEJB {

@PersistenceContext(unitName =MyPrototype)
private EntityManager em;

@Override
public List< Cars> getCars(){
return(List< Cars>)em.createNamedQuery(Cars.findAll)。setMaxResults(200).getResultList();
}

}

* 加入澄清我如何运行查询



就像我说过的,我可以通过EHCache监视器看到内存中的项数,因此我注意到以下内容:
- ehcache配置是属性加载的元素即将过期
- 当查询在它们仍然活着时运行时(它们在第一个查询后N秒过期),元素过期不会被重置。



再次;我非常喜欢java,所以我可能会缺少基本概念。



感谢您的阅读!



使用JPA API,直接使用查询提示完成查询定义,或每次创建查询时:

  @NamedQuery(name =Cars.findAll,
query = SELECT d FROM Cars d,
hints = {@QueryHint(name =org.hibernate.cacheable,value =true)})

既然查询是可缓存的,Hibernate将在第一次执行查询时从数据库加载汽车的ID,然后从查询缓存中加载。然后相应的汽车本身将从实体缓存中加载。


I'm trying to implement EHCache into my working prototype, where I have a javax.persistence.Entity representing a table on my database (MySQL, mysql-connector-java-5.1.20.jar), which be provided as XML to the consumers.

The issue I'm facing is that seems Hibernate still retrieving the data from the database, even when EHCache stores the query result on memory.

I'm using the EHCache monitor to see the count of items in memory, and changing the data directly on database before the cache expires to know if the cached data is actually used.

I been looking for a replication for this issue without succeed, so maybe I'm missing something (I just geting into the java world).

My files

pom.xml

<dependency>
    <groupId>org.hibernate</groupId>
    <artifactId>hibernate-validator</artifactId>
    <version>4.3.0.Final</version>
</dependency>
<dependency>
    <groupId>org.hibernate</groupId>
    <artifactId>hibernate-entitymanager</artifactId>
    <version>4.1.4.Final</version>
</dependency>
<dependency>
    <groupId>org.hibernate</groupId>
    <artifactId>hibernate-ehcache</artifactId>
    <version>4.1.4.Final</version>
</dependency>
<dependency>
    <groupId>net.sf.ehcache</groupId>
    <artifactId>ehcache-core</artifactId>
    <version>2.5.2</version>
</dependency>
<dependency>
    <groupId>org.terracotta</groupId>
    <artifactId>ehcache-probe</artifactId>
    <version>1.0.2</version>
</dependency>

Entity class

package myPrototype.entities

import javax.persistence.Cacheable;
import javax.persistence.Entity;
import javax.persistence.NamedQueries;
import javax.persistence.NamedQuery;
import javax.persistence.Table;
import javax.xml.bind.annotation.XmlRootElement;
import org.hibernate.annotations.Cache;
import org.hibernate.annotations.CacheConcurrencyStrategy;

@Entity @Cacheable
@Cache(usage=CacheConcurrencyStrategy.READ_ONLY)
@Table(name = "Cars")
@XmlRootElement
@NamedQueries({
    @NamedQuery(name = "Cars.findAll", query = "SELECT d FROM Cars d"),
    [...]
public class Cars implements Serializable {
    private static final long serialVersionUID = 1L;
    @Basic(optional = false)
        @NotNull
        @Column(name = "id")
    @ReferenceField
    private int id;
    [...]

ehcache.xml

<?xml version="1.0" encoding="UTF-8"?>
<ehcache>
  <cache name="myPrototype.entities.Cars"
    maxElementsInMemory="500"
    eternal="false"
    overflowToDisk="false"
    timeToIdleSeconds="60"
    timeToLiveSeconds="120" />
</ehcache>

* I tried setting eternal="true", but the result still the same

persistence.xml

<?xml version="1.0" encoding="UTF-8"?>
<persistence version="2.0" xmlns="http://java.sun.com/xml/ns/persistence" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/persistence http://java.sun.com/xml/ns/persistence/persistence_2_0.xsd">
  <persistence-unit name="MyPrototype" transaction-type="JTA">
    <provider>org.hibernate.ejb.HibernatePersistence</provider>
    <jta-data-source>java:app/jdbc/mysqlserver/prototype</jta-data-source>
    <exclude-unlisted-classes>false</exclude-unlisted-classes>
    <shared-cache-mode>ENABLE_SELECTIVE</shared-cache-mode>
    <properties>
      <!-- property name="hibernate.cache.region.factory_class" value="org.hibernate.cache.ehcache.SingletonEhCacheRegionFactory"/ -->
      <property name="hibernate.cache.region.factory_class" value="org.hibernate.cache.ehcache.EhCacheRegionFactory" />
      <property name="hibernate.cache.use_second_level_cache" value="true"/>
      <property name="hibernate.cache.use_query_cache" value="true"/>
      <property name="hibernate.cache.region_prefix" value=""/>
    </properties>
  </persistence-unit>
</persistence>

* I tried switching between SingletonEhCacheRegionFactory and EhCacheRegionFactory

EJB

import myPrototype.entities.Cars
import java.util.Date;
import java.util.List;
import javax.ejb.Stateless;
import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;

@Stateless
public class CarsEJB {

    @PersistenceContext(unitName="MyPrototype")
    private EntityManager em;

    @Override
    public List<Cars> getCars() {
        return (List<Cars>)em.createNamedQuery("Cars.findAll").setMaxResults(200).getResultList();
    }

}

* Added to clarify how I run the query

Like I said, I can see a count of items in memory through EHCache monitor, so I noted the following: - The ehcache configuration is property loaded elements are expiring - The elements expiration not being reseted when the query runs while they still alive (they expired N seconds after the first query).

Again; I'm quite a newbie with java, so asume I could be missing basic concepts.

Thanks for reading!

解决方案

Hibernate will never execute queries on your cache. What it can do is execute a query on the database, cache the results, and return these cached results the next time you execute the same query, with the same parameters. But to do that, the query, each time it's executed, must be cacheable.

WIth the JPA API, this is done using query hints, directly on the named query definition, or each time you create a query:

@NamedQuery(name = "Cars.findAll", 
            query = "SELECT d FROM Cars d",
            hints = {@QueryHint(name = "org.hibernate.cacheable", value = "true")})

Now that the query is cacheable, Hibernate will load the IDs of the cars from the database the first time this query is executed, and from the query cache afterwards. Then the corresponding cars themselves will be loaded from the entity cache.

这篇关于JPA + Hibernate + EHCache,出乎意料的行为的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆