gpt4 book ai didi

java - 从 JpaRepository 检索对象后,延迟加载在简单的 Hibernate/Spring 启动示例中不起作用

转载 作者:行者123 更新时间:2023-12-01 17:20:05 24 4
gpt4 key购买 nike

我开发了一个 Spring boot 应用程序,该应用程序在实体之间的所有关系上使用 fetch = EAGER 注释。我认为这会导致严重的性能问题,而且我后来了解到这似乎是一种反模式( https://vladmihalcea.com/the-open-session-in-view-anti-pattern/https://vladmihalcea.com/eager-fetching-is-a-code-smell/ )。

我一直在试图弄清楚如何正确使用延迟加载。我想出了一个最小的例子,可以让我重现它。

TestJpa应用程序

package com.myproject.testJpa;

import com.myproject.testJpa.entity.Host;
import com.myproject.testJpa.entity.HostSet;
import com.myproject.testJpa.entity.repository.HostRepository;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.CommandLineRunner;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.Bean;
import com.myproject.testJpa.entity.repository.HostSetRepository;
import org.springframework.transaction.annotation.Transactional;

@SpringBootApplication
public class TestJpaApplication {
private final Logger logger = LoggerFactory.getLogger(TestJpaApplication.class);

@Autowired
private HostRepository hostRepository;

@Autowired
private HostSetRepository hostSetRepository;

public static void main(String[] args) {
SpringApplication.run(TestJpaApplication.class, args);
}

@Bean
public CommandLineRunner demo() {
return (args) -> {
init();
fetch();
};
}

private void init() {
Host host1 = findOrCreateHost("HOST 1");
Host host2 = findOrCreateHost("HOST 2");
Host host3 = findOrCreateHost("HOST 3");

HostSet hostSet = findOrCreateHostSet("HOST SET 1");

hostSet.addHost(host1);

hostSetRepository.save(hostSet);

hostRepository.save(host1);
hostRepository.save(host2);
hostRepository.save(host3);
}

@Transactional
private void fetch() {
HostSet hostSet = hostSetRepository.findOneByNameIgnoreCase("HOST SET 1");

for(Host host : hostSet.getHosts()) {
logger.debug("Host: {}", host);
}
}

public Host findOrCreateHost(String name) {
Host host = hostRepository.findOneByNameIgnoreCase(name);

if(host == null) {
host = new Host(name);

hostRepository.save(host);
}
return host;
}

public HostSet findOrCreateHostSet(String name) {
HostSet hostSet = hostSetRepository.findOneByNameIgnoreCase(name);

if (hostSet == null) {
hostSet = new HostSet(name);
hostSetRepository.save(hostSet);
}

logger.debug("Host: {}", hostSet.getHosts());

return hostSet;
}
}

主机

package com.myproject.testJpa.entity;

import java.util.HashSet;
import java.util.Set;

import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.ManyToMany;

@Entity
public class Host {

@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Column(name = "host__id")
private Long id;

private String name;

@ManyToMany(mappedBy = "hosts")
private Set<HostSet> hostSets = new HashSet<>();

public Host() {

}

public Host(Long id) {
this.id = id;
}

public Host(String name) {
this.name = name;
}

public Long getId() {
return id;
}

public String getName() {
return name;
}

public void setName(String name) {
this.name = name;
}

public Set<HostSet> getHostSets() {
return hostSets;
}

public void setHostSets(Set<HostSet> hostSets) {
this.hostSets = hostSets;

hostSets.forEach(hs -> addToHostSet(hs));
}

public Host addToHostSet(HostSet hostSet) {
if (!hostSets.contains(hostSet)) {
hostSets.add(hostSet);
hostSet.getHosts().add(this);
}

return this;
}

public Host removeFromHostSet(HostSet hostSet) {
if (hostSets.contains(hostSet)) {
hostSets.remove(hostSet);
hostSet.getHosts().remove(this);
}

return this;
}
}

主机集

package com.myproject.testJpa.entity;

import java.util.HashSet;
import java.util.Set;

import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.JoinColumn;
import javax.persistence.JoinTable;
import javax.persistence.ManyToMany;



@Entity
public class HostSet {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Column(name = "host_set__id")
private Long id;

private String name;

@ManyToMany
@JoinTable(
name = "host_set__host",
joinColumns = @JoinColumn(name = "host_set__id"),
inverseJoinColumns = @JoinColumn(name = "host__id")
)
private Set<Host> hosts = new HashSet<>();

public HostSet() {
}

public HostSet(Long id) {
this.id = id;
}

public HostSet(String name) {
this.name = name;
}

public Long getId() {
return id;
}

public String getName() {
return name;
}

public void setName(String name) {
this.name = name;
}

public Set<Host> getHosts() {
return hosts;
}

public void setHosts(Set<Host> hosts) {
this.hosts = hosts;
}

public HostSet addHost(Host host) {
if(!hosts.contains(host)) {
hosts.add(host);
host.addToHostSet(this);
}

return this;
}

public HostSet removeHost(Host host) {
if(hosts.contains(host)) {
hosts.remove(host);
host.removeFromHostSet(this);
}

return this;
}
}

主机存储库

package com.myproject.testJpa.entity.repository;

import com.myproject.testJpa.entity.Host;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.stereotype.Repository;

@Repository
public interface HostRepository extends JpaRepository<Host, Long> {
public Host findOneByNameIgnoreCase(String name);
}

HostSetRepository

package com.myproject.testJpa.entity.repository;

import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.stereotype.Repository;

import com.myproject.testJpa.entity.HostSet;

@Repository
public interface HostSetRepository extends JpaRepository<HostSet, Long> {
public HostSet findOneByNameIgnoreCase(String name);
}

当我运行应用程序时,在 fetch() 方法中循环检索的 hostSet 的主机时,它会抛出以下错误。

Caused by: org.hibernate.LazyInitializationException: failed to lazily initialize a collection of role: com.myproject.testJpa.entity.HostSet.hosts, could not initialize proxy - no Session
at org.hibernate.collection.internal.AbstractPersistentCollection.throwLazyInitializationException(AbstractPersistentCollection.java:606)
at org.hibernate.collection.internal.AbstractPersistentCollection.withTemporarySessionIfNeeded(AbstractPersistentCollection.java:218)
at org.hibernate.collection.internal.AbstractPersistentCollection.initialize(AbstractPersistentCollection.java:585)
at org.hibernate.collection.internal.AbstractPersistentCollection.read(AbstractPersistentCollection.java:149)
at org.hibernate.collection.internal.PersistentSet.iterator(PersistentSet.java:188)
at com.myproject.testJpa.TestJpaApplication.fetch(TestJpaApplication.java:58)
at com.myproject.testJpa.TestJpaApplication.lambda$demo$0(TestJpaApplication.java:34)
at org.springframework.boot.SpringApplication.callRunner(SpringApplication.java:784)

我尝试在多个地方添加 @Transactional 注释,但没有成功。这让我发疯,因为我不知道自己做错了什么。

感谢您的帮助!

最佳答案

事实证明,@Transactional 在 TestJpaApplication 类中不起作用(我没有在匿名方法上设置它,不知道如何设置或是否可能)。

我将内容移至单独的服务并且它有效。

关于java - 从 JpaRepository 检索对象后,延迟加载在简单的 Hibernate/Spring 启动示例中不起作用,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/61311221/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com