如何急切地获取JPA和Hibernate中的数据,以便在会话之外使用?
我不熟悉Hibernate和JPA,但似乎无法让它工作 这些模型是持久化的,其中如何急切地获取JPA和Hibernate中的数据,以便在会话之外使用?,hibernate,jpa,spring-data-jpa,Hibernate,Jpa,Spring Data Jpa,我不熟悉Hibernate和JPA,但似乎无法让它工作 这些模型是持久化的,其中EntityHistory在EntityHistoryChange表中有一组链接的更改: @Table @RooJavaBean @RooJpaActiveRecord public class EntityHistory { @Id @GeneratedValue(strategy = GenerationType.AUTO) @Column(name = "id") privat
EntityHistory
在EntityHistoryChange
表中有一组链接的更改:
@Table
@RooJavaBean
@RooJpaActiveRecord
public class EntityHistory {
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
@Column(name = "id")
private Long id;
@OneToMany(cascade = CascadeType.ALL, mappedBy = "history")
private Set<EntityHistoryChange> changes = new HashSet<>();
}
@Table
@AssociationOverride(name="history", joinColumns = @JoinColumn(name ="entityHistoryId"))
@RooJavaBean
@RooJpaActiveRecord
public class EntityHistoryChange {
@Lob
@Type(type = "org.hibernate.type.TextType")
private String change;
}
@表格
@爪哇豆
@RooJPA活动记录
公共类实体历史{
@身份证
@GeneratedValue(策略=GenerationType.AUTO)
@列(name=“id”)
私人长id;
@OneToMany(cascade=CascadeType.ALL,mappedBy=“history”)
私有集更改=新HashSet();
}
@桌子
@AssociationOverride(name=“history”,joinColumns=@JoinColumn(name=“entityHistoryId”))
@爪哇豆
@RooJPA活动记录
公共类EntityHistoryChange{
@高球
@类型(Type=“org.hibernate.Type.TextType”)
私有字符串更改;
}
然后,我需要一次访问所有这些数据,以便将其序列化以进行计划的导出
我有一个带有计划作业的服务:
// Trying to fetch entire object so can use it outside of session
@Service
public class ScheduledExecutor {
@Scheduled(cron = "0 05 0 * * ?")
public void extractHistory() {
long lastId = 12345l;
List<EntityHistory> history = findHistoriesWithIdGreater(lastId);
for(EntityHistoryChange change : history.get(6).getChanges()){
logger.info(" change is: " + change.getChange());
}
}
public static List<EntityHistory> findHistoriesWithIdGreater(Long lastId) {
TypedQuery<EntityHistory> query = entityManager().createQuery(
"select a from EntityHistory a join fetch a.changes c where a.id > :lastId order by a.id",
EntityHistory.class);
query.setParameter("lastId", lastId);
return query.getResultList();
}
}
//尝试获取整个对象,以便可以在会话之外使用它
@服务
公共类调度执行器{
@已计划(cron=“0 05 0**?”)
public void extractHistory(){
长lastId=12345l;
List history=findHistorieswithId大于(lastId);
for(EntityHistoryChange更改:history.get(6.getChanges()){
info(“更改为:+change.getChange());
}
}
公共静态列表查找具有更大ID的历史(长lastId){
TypedQuery query=entityManager().createQuery(
“从EntityHistory a join fetch a.changes a.c中选择a.id>:lastId order by a.id”,
实体历史类);
setParameter(“lastId”,lastId);
返回query.getResultList();
}
}
但当它运行时,我一直会遇到以下错误:
org.hibernate.LazyInitializationException:无法执行请求的延迟初始化[com.company.model.EntityHistory.changes]-没有会话和设置不允许在会话外部加载
我认为,通过在JPQL查询中放入
连接获取
,它应该急切地获取该连接中的所有数据
fetch应该完成这项工作,但这只是对hibernate的一个建议,如果需要的话
没有,那么这可能是复杂映射的结果
因此,尝试一种不同的方法,我能够通过以下方式构建DAO来实现我所追求的目标:
/** DAO to interact with EntityHistory records */
public interface EntityHistoryDao extends JpaRepository<EntityHistory, Long> {
/** Returns EntityHistory records with IDs greater than the given ID */
@QueryHints(value = @QueryHint(name = org.hibernate.jpa.QueryHints.HINT_FETCH_SIZE, value = "500"))
Stream<EntityHistory> findByIdGreaterThanOrderByIdAsc(Long id);
}
此注释将实现以下功能:
@EntityGraph(attributePaths = { "changes" })
Stream<EntityHistory> findByIdGreaterThanOrderByIdAsc(Long id);
@EntityGraph(attributePath={“changes”})
流findByidCreaterAnorderByIdasc(长id);
它将创建一个连接查询(列出的属性将被急切地加载),因此所有数据都将在一个查询中加载,因此您甚至不需要服务方法上的@Transactional
注释
编辑 我忽略了
流
返回类型。(我以前从未在存储库中将流用作返回类型)
我仍然相信,如果您将返回类型更改为
List
,那么它就会工作。生成的SQL语句是什么样子的?@SimonMartinelli我不确定。我怎样才能打开它们看呢?根据Andronicus的反馈,听起来JPQL中的“fetch”命令被hibernate视为一个提示,不一定强制执行。无论如何,我确实找到了一个适合我的目的的解决方案,我会在一个新的答案中更新。我测试了这个,但事实并非如此。删除服务方法上的@Transactional
注释,在DAO方法上应用@EntityGraph
注释会产生类似的问题:InvalidDataAccessApiUsageException:您试图执行流式查询方法,而不使用保持连接打开的周围事务,以便流可以实际使用。确保使用流的代码使用@Transactional或任何其他方式声明(只读)事务。
使用列表而不是流来尝试它
再次导致原始错误:LazyInitializationException:无法执行请求的延迟初始化[com.company.model.EntityHistory.changes]-无会话和设置不允许在会话之外加载
@EntityGraph(attributePaths = { "changes" })
Stream<EntityHistory> findByIdGreaterThanOrderByIdAsc(Long id);