繁体   English   中英

JPA / Eclipselink缓存寿命

[英]JPA/Eclipselink cache life span

1.-我正在使用EcipseLink 2.0.0来运行Glassfish 2.1,因此实际上使用的是JPA 1.0规范,并且我有一个无状态EJB,可用于查找实体。 据我所知,JPA 1.0定义了一个在持久性上下文级别(无状态EJB的事务级别)工作的L1高速缓存,但是我不知道为什么下一个代码在同一事务中打印“不相同的实例”。

@Stateless
@TransactionAttribute(TransactionAttributeType.REQUIRES_NEW)    
public class EntityServiceBean implements EntityServiceLocal {
    @PersistenceContext(unitName = "Model")
    private EntityManager entityManager;
    @Override
    public <T> T find(Class<T> type, Object id) {
        T entity = entityManager.find(type, id);
        if(entity != entityManager.find(type, id)) {
            System.out.println("Not same instance");
        }
        return entity;
    }
    ....
}

我什至尝试了该属性:

<property name="eclipselink.cache.type.default" value="Full"/>

在persistence.xml文件中,但功能相同。

2.-如果可能的话,我真正想要实现的是对我的无状态EJB的多次调用返回相同的实例,换句话说,跨事务和使用无状态EJB的持久性上下文的JPA缓存寿命,例如:

... // POJO class
EntityServiceLocal entityService = ...
Product pA = entityService.find(Product.class, 1l);
...
Product pB = entityService.find(Product.class, 1l);
System.out.println("Same instance?" + pA == pB); // TRUE

我读到许多JPA实现都使用了跨越多个持久性上下文的L2缓存(现在在JPA 2.0中定义),即使使用JPA 1.0也是如此,但我不知道是否误解了L2缓存概念和/或缺少任何配置。

这可能吗? 或者我该怎么做才能避免每分钟从数据库读取超过2万个实体来更新需要的实体?

我正在将Glassfish 2.1与EcipseLink 2.0.0一起使用,因此实际上使用的是JPA 1.0规范,并且我有一个无状态EJB,可用于查找其他实体。 据我所知,JPA 1.0定义了一个在持久性上下文级别(无状态EJB的事务级别)工作的L1高速缓存,但是我不知道为什么下一个代码在同一事务中打印“不相同的实例”。

非常不可思议,在Java EE上下文中的事务内肯定应该维护对象标识。 JPA Wiki书中对此进行了很好的记录:

对象身份

Java中的对象身份意味着如果两个变量(x,y)引用相同的逻辑对象,则x == y返回true。 意思是两者都引用相同的东西(都是指向相同内存位置的指针)。

在JPA中,对象标识在事务中(通常)在同一EntityManager中维护。 在JEE管理的EntityManager中是一个例外,对象标识仅在事务内部维护。

因此,在JPA中,以下是正确的:

 Employee employee1 = entityManager.find(Employee.class, 123); Employee employee2 = entityManager.find(Employee.class, 123); assert (employee1 == employee2); 

无论如何访问对象,这都适用:

 Employee employee1 = entityManager.find(Employee.class, 123); Employee employee2 = employee1.getManagedEmployees().get(0).getManager(); assert (employee1 == employee2); 

在JPA中,不跨EntityManager维护对象身份。 每个EntityManager都维护自己的持久性上下文及其对象的事务状态。

因此,在JPA中,以下是正确的:

 EntityManager entityManager1 = factory.createEntityManager(); EntityManager entityManager2 = factory.createEntityManager(); Employee employee1 = entityManager1.find(Employee.class, 123); Employee employee2 = entityManager2.find(Employee.class, 123); assert (employee1 != employee2); 

对象标识通常是一件好事,因为它避免让您的应用程序管理对象的多个副本,并且避免应用程序更改一个副本,而不能更改另一个副本。 (在JEE中)不同的EntityManager或事务不维护对象身份的原因是,每个事务必须将其更改与系统的其他用户隔离。 通常这也是一件好事,但是它确实要求应用程序知道副本,分离的对象和合并。

某些JPA产品可能具有只读对象的概念,其中可以通过共享对象缓存在EntityManager之间维护对象标识。

而且我无法在Java SE环境中(在事务内和相同的EntityManager )重现EclipseLink 2.0的问题-抱歉,我不会在GF 2.1下进行测试。

我什至尝试使用以下属性: persistence.xml文件中的<property name="eclipselink.cache.type.default" value="Full"/> ,但功能相同

L1缓存没有什么可“激活”的。

如果可能的话,我真正想要实现的是对我的无状态EJB的多次调用返回相同的实例,换句话说,使用无状态EJB跨事务和持久性上下文跨越了JPA缓存寿命(...):

L2缓存确实是跨多个事务和EntityManager的缓存,大多数JPA提供程序都支持L2缓存。 但是,尽管L2缓存将减少数据库命中率,但并非所有提供程序都可以保证对象标识。

例如,使用Hibernate时,默认情况下不会启用L2缓存,因为Hibernate不会将实体本身放入缓存中,因此您不会获得对象标识。

使用EclipseLink,默认情况下会启用L2 缓存 ,您将根据缓存类型获得对象标识 默认值是大小为100SOFT-WEAK高速缓存,它确实保留了对象标识。 尽管您可以很好地配置事物(降低到实体级别),但无论是否为分布式环境 ,事物都应默认工作。

也可以看看

您还设置了哪些其他设置,以及如何映射课程?

同一事务中的两个发现应该始终是同一实例。

如果将对象标记为对象,或者查询为只读(@ReadOnly,“ eclipselink.read-only” =“ true”),则可以使find()返回跨事务边界的相同实例。 您将需要确保将其用作只读。 试图允许更新由不同事务共享的同一实例是不可能的,也不是一个好主意。

我们发现Eclipselink L2实体缓存似乎并没有完成它应该做的事情。 我们从数据库保留在L2高速缓存中的对象相对较少,但是我们的内存使用率在24小时内一直失控,直到我们用完堆(价值4GB)。 我已经分析了该应用程序,并确认内存使用量来自Eclipselink的L2缓存。 我们使用的是SOFT-WEAK,它绝不会撤离所有旧对象(文档建议这样做),并创建多个属性相同的对象实例(文档建议这样做)不应这样做),出于善意,这是一个只读应用程序。 我们也无法在集群环境中以任何方式进行缓存协调工作。 我们已经有三位资深Java开发人员,每位都有十多年的经验,其中一位实际上在IBM的Java实现方面工作过,但是仍然无法成功实现任何缓存协调功能,并且在上一个过程中定期花时间在问题上甚至六个月的时间都在Eclipselink源中进行跟踪,以找出问题所在。 每隔24小时重新启动我们的应用程序将变得非常烦人,至此,我即将完成L2缓存。 我只希望没有它,我们就能获得可接受的性能,至少Eclipselink JPA 1实现可以设法进行并行读取,而这些并行读取似乎已经在JPA 2中消失了。数据库实现者几年前用MVCC解决了这一问题,为什么会有一套智能鉴于Java开发人员已经完成,因此无法管理同样的壮举吗? 我们要做的就是将其本质上移至上游,并将数据表示为对象,而不是元组和页面。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM