在简单的HibernateSpring启动示例中,从JpaRepository中检索对象后,懒惰加载不起作用。

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

我一直在试图找出如何正确使用懒惰加载。我想出了一个最小的例子,让我可以重现它。

测试JpaApplication

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;
    }
}

HostRepository

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的hosts时,它抛出了以下错误。

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注解,但没有用。这快把我逼疯了,因为我不知道自己做错了什么。

谢谢你的帮助!我已经开发了一个Spring引导应用程序。

解决方案:

原来在TestJpaApplication类中,@Transactional没有工作(我没有在匿名方法上设置它,不知道如何设置,也不知道是否可能)。

我把内容移到一个单独的服务中,就可以了。

给TA打赏
共{{data.count}}人
人已打赏
未分类

使用Apache Commons VFS上传至远程FTP服务器。

2022-9-8 2:56:36

未分类

lat

2022-9-8 2:56:38

0 条回复 A文章作者 M管理员
    暂无讨论,说说你的看法吧
个人中心
购物车
优惠劵
今日签到
有新私信 私信列表
搜索