2014-10-20 73 views
0

我们在我们的项目中使用Spring Data(版本1.3.2)和OpenJPA(版本2.2.2)。 OneToOne关系在我们的实体中面临延迟加载字段的问题。我将用一个例子来描述这个问题:我们有两个实体(称为Person和Address)。 Person和Address之间有一对一的关系。下面给出的是Person和Address实体的代码示例(getter和setter冷落为了简洁):Spring数据+打开jpa +延迟加载+ OneToOne关系

@Entity 
public class Person { 

@Id 
@GeneratedValue(strategy = GenerationType.AUTO) 
private int id; 

private String firstName; 

private String lastName; 

@OneToOne(mappedBy = "person", fetch = FetchType.LAZY) 
private Address address; 
} 

@Entity 

public class Address { 

@Id 
@GeneratedValue(strategy = GenerationType.AUTO) 
private int id; 

private String streetAddress; 

private String city; 

private String zipCode; 

@OneToOne 
@JoinColumn(name="PERSON_ID") 
private Person person; 
} 

然后,我们从JpaRepository延伸到我们提供了基本的CRUD操作这两个实体创建AddressRepository和PersonRepository。

在我们的应用程序中Person实体首先被创建,没有任何地址与它关联。然后通过在地址实例中设置适当的人员实体,在稍后的时间点创建地址实体。直到这一点都按预期工作。

现在,如果通过传递适当的ID来查询Person实体使用PersonRepository的findOne方法,那么返回的Person实例没有填充地址字段。当我们访问由PersonRepository返回的Person的地址字段时,它恰好为null。如果有与Person关联的Address实体,我们期待Person中的地址字段可用。假设提取类型设置为LAZY,这意味着只有当我们尝试访问地址字段时才会加载该提取类型。当我们直接使用JPA API时(使用EntityManager.find()方法),这就是它的工作原理。

这段代码在我们使用hibernate的时候用得很好。由于某些法律原因,我们必须将我们的JPA提供程序更改为OpenJPA,并停止工作。使用OpenJPA进行延迟加载OneToOne工作时,有什么我们应该做的不同吗?

注意:我们已启用L2缓存。我们发现OpenJPA存在L2高速缓存问题,并在OpenJPA上打开了这个缺陷(https://issues.apache.org/jira/browse/OPENJPA-2522)。但是,即使存在这种缺陷,也有一种解决方法(使用entitymanagerfactory的evict方法将实体从L2缓存中删除),并使用JPA API,我们可以使其运行。但是,对于春季数据,我们发现即使在使用此解决方法时也存在此问题。我们这样做是通过提供JPA储存库的实体管理器工厂-REF,然后注入我们的豆子一样电动势从缓存中驱逐实体:

<jpa:repositories base-package="com.abc.dsp.spring.data.repository" entity-manager-factory-ref="emf"/> 

由于我们的项目广泛使用的弹簧的数据是难以转向使用纯粹的JPA API。此外,正如在某些回答herehere中所提到的,由于广泛的代码影响,我们正试图避免更改为渴望获取类型或自定义设置方法。

更新: 使用自定义setter方法也不起作用。正在工作的是将获取类型更改为EAGER。但是,我们希望将fetchType保持为LAZY,因为在大多数情况下,我们不需要关联的对象,而且该对象非常重。

回答

0

好的,所以我想清楚为什么解决方法(从缓存驱逐实体)不起作用。我试图访问交易边界以外的人的地址字段。我用findOne查询Person,并从一个用@Transactional注解注释的方法返回这个实例。我正试图访问未使用@Transactional批注注释的调用方法中返回的Person实例的地址字段。一旦我使用@Transactional注解访问方法中的地址字段,那么一旦我使用了解决方法,所有事情都能正常工作。我刚刚捕获的解决办法在这里再次为便于参考,为别人:

1)由JPA指定实体管理裁判注入在JPA库EntityManagerFactory的:库标签

<jpa:repositories base-package="com.ge.dsp.spring.data.repository" entity-manager-factory-ref="emf"/> 

这emf为一个是在你的spring应用程序上下文中创建的。

2)现在在您的类中注入相同的emf,并调用使用@Transactional注释注释的DAO方法。

emf.getCache().evict(Class cls, Object primaryKey) 

这将确保未来findOne /的findAll调用将得到高速缓存未命中并返回正确:之后您已成功通过调用相应的保存/上DAO创建方法,EMF的调用下面的方法来驱逐实体创建实体构造实体。请注意,这是由于openJPA中的错误所致(https://issues.apache.org/jira/browse/OPENJPA-2522