我在使用 JPA 和 Spring 从数据库获取一些惰性数据时遇到了一些问题。
我必须为将来安排一些数据库操作,但是当它们实际运行时,我遇到了 LazyInitializationException。
这是消息:
failed to lazily initialize a collection of role: de.db.ewb.database.entity.VorgangDO.zuege: could not initialize proxy - no Session
根据Stackoverflow和文档上的一些信息,当离开最初从数据库获取VorgangDO对象的线程范围时,我的事务被关闭,因此该对象不再绑定到JPA和Hibernate。这意味着不再有延迟加载。
我的第一个想法是再次调用我的存储库的
.findById()
方法,但在新范围内。所以我将得到一个再次绑定到 JPA 的新对象。但生成的对象将所有字段设置为 null,因此我将 @Transaction
注释添加到我的 run()
方法中。
结果是字段现在已填充,但是当我尝试访问应该延迟加载的数据集合时,我仍然遇到上述异常。
即使我试图在同一方法中获取这些数据,该方法也用
@Transactional
和这一行 vorgangRepository.findById(55).get().getZuege().size()
注释。
这是我的代码:
@Service
public class CSPService {
@Autowired
private VorgangRepository vorgangRepository;
private ThreadPoolTaskScheduler threadPoolExecuter;
private class CSPRetry implements Runnable {
...
@Override
@Transactional
public void run() {
...
vorgangRepository.findById(55).get().getZuege().size();
...
}
...
}
@PostConstruct
private void init() {
threadPoolExecuter = new ThreadPoolTaskScheduler();
threadPoolExecuter.setPoolSize(10);
threadPoolExecuter.setThreadNamePrefix("CSPRetryTaskScheduler");
threadPoolExecuter.setDaemon(true);
threadPoolExecuter.initialize();
}
public void sendToCSP(VorgangDO vorgang) {
...
}
public void retry() {
...
threadPoolExecuter.schedule(new CSPRetry(....), LocalDateTime.now().plusSeconds(30).toInstant(OffsetDateTime.now().getOffset()));
...
}
}
@Entity
@Indexed
@Table(name = "VORGAENGE")
@SequenceGenerator(name = "hibernate_sequence_abstract_vorgang", sequenceName = "hibernate_sequence_vorgang", allocationSize = 1)
public class VorgangDO extends AbstractVorgangDO implements EntityWithRegions {
...
}
@MappedSuperclass
public class AbstractVorgangDO extends BaseDO<VorgangTO> {
...
@IndexedEmbedded
@OneToMany(cascade = CascadeType.ALL, fetch = FetchType.LAZY)
@JoinColumn(name = "vorgang_id")
@IndexingDependency(reindexOnUpdate = ReindexOnUpdate.SHALLOW)
private List<ZugDO> zuege;
...
}
public interface VorgangRepository extends CrudRepository<VorgangDO, Long> {
...
}
有人知道为什么这仍然失败吗?即使我在之前调用过
.findById()
的同一个事务中初始化集合?
我将代码精简到最少,因为它太多了。如果缺少什么,我会提供缺少的部分。
您需要在 @OneToMany 注释中更新 fetch=FetchType.EAGER 以自动拉回 @Embeddable 类:
@OneToMany(cascade = CascadeType.ALL, fetch = FetchType.EAGER)
在打开的 Hibernate 会话上下文之外访问延迟加载的对象将导致 LazyInitializationException。 Hibernate 创建一个动态代理对象子类,仅当我们第一次使用该对象时才会访问数据库。 当我们尝试使用代理对象从数据库中获取延迟加载的对象(延迟加载意味着该对象只有在代码中访问时才会加载到会话上下文中),但 Hibernate 会话(会话是持久化上下文,代表应用程序和数据库之间的对话)已经关闭。