【问题标题】:spring-data-jpa hibernate : failed to lazily initialize a collection, could not initialize proxy - no Sessionspring-data-jpa hibernate:无法延迟初始化集合,无法初始化代理 - 没有会话
【发布时间】:2021-03-13 14:42:16
【问题描述】:

当我试图懒惰地读取子实体列表时,我(间歇性地)收到此错误。

failed to lazily initialize a collection of role: G.h, could not initialize proxy - no Session

关于这个错误,我浏览了关于 SO 的帖子列表。我所能找到的只是做 EAGER fetch 或使用 hibernate.enable_lazy_load_no_trans 属性。我也不想这样做,因为它们是反模式。

而且我在从数据库读取数据的类级别上确实有@Tranastional(readOnly=true),所以我希望休眠会话在事务完成之前一直打开。

此外,此错误仅偶尔弹出一次。大多数时候根本没有问题。另一件事是,我可以确认实体是延迟加载的(除了我明确指定 EAGER 的地方),因为我可以看到在读取实体时记录了 sql 语句。

这是我的代码在坚果壳中的样子。

@Service
@Transactional(readOnly = true)
public class AService {

 public void someMethod(Long id) {
        Optional<A> a = ARepository.findById(id); // This is a standard JPA repository interface where I have defined a method findById
        final Optional<G> g = getG(a.get());

        if (g.isPresent()) {
            for (final H h : g.get().getH()) { // Exception is thrown exactly at line ..getH()
               
            }
        }
        
    }

    private Optional<G> getG(final A a) {
        return a.getB()
                .getD()
                .getF()
                .flatMap(F::getG);
    }
}

@Entity
public class A implements Serializable {

    @ManyToOne
    private AGroup aGroup;

    @Transient
    public Optional<B> getB() {
        return getC().map(C::getB);
    }

    public Optional<C> getC() {
        if (aGroup != null) {
            return Optional.ofNullable(aGroup.getC());
        }

        return empty();
    }
}


@Entity
public class AGroup implements Serializable {

    @ManyToOne
    private C c;

    @OneToMany(fetch = EAGER, cascade = ALL, mappedBy = "aGroup")
    private final Set<A> as = new HashSet<>();
}


@Entity
public class C implements Serializable {

    @OneToMany(fetch = LAZY, cascade = ALL, mappedBy = "c")
    private List<AGroup> aGroups = new ArrayList<>();

    @ManyToOne
    private B b;
}

@Entity
public class B implements Serializable {

    @OneToMany(fetch = LAZY, mappedBy = "b")
    private Set<C> cs = new HashSet<>();

    @ManyToOne(fetch = LAZY)
    private D d;
}


@Entity
public class D implements Serializable {

    @OneToMany(fetch = LAZY, mappedBy = "d")
    private final List<B> bs = new ArrayList<>();

    public Optional<F> getF() {
        // based on some other fields return Optional.of(F)
    }
}

@Entity
public class F implements Serializable {

    @ManyToOne
    private G g;

    public Optional<G> getG() {
        return Optional.ofNullable(g);
    }
}

@Entity
public class G implements Serializable {

    @OneToMany(mappedBy = "g")
    private List<F> fs = new ArrayList<>();

    @OneToMany(cascade = ALL, mappedBy = "g")
    private List<H> hs = new ArrayList<>();
}

@Entity
public class H {

    @ManyToOne
    private G g;
}

任何人都知道是什么导致了这个问题(更重要的是,为什么会间歇性发生这种情况)

我正在使用 spring-data-jpa。这是一个spring-boot项目。请求来自 web 层(Rest Controller)

【问题讨论】:

    标签: spring-boot hibernate spring-data-jpa spring-data lazy-loading


    【解决方案1】:

    看起来底层的 Hibernate 会话在某个时候关闭/重新打开,这使得 G 分离。我不知道ARepository.findById 做了什么或者你有什么样的拦截器。

    【讨论】:

    • 感谢您的回复。没有拦截器。 ARepository 是一个 JpaRepository,其定义如下 public interface ARepository extends JpaRepository&lt;A, Long&gt; { Optional&lt;A&gt; findById(Long id); }
    • 您可以在构造函数或SessionImpl 的close 方法中放置一个断点,以查看创建/关闭实例的位置以进一步调试。如果这没有帮助,请在问题跟踪器 (hibernate.atlassian.net) 中创建一个问题,并使用重现问题的测试用例 (github.com/hibernate/hibernate-test-case-templates/blob/master/…)。
    猜你喜欢
    • 2022-07-08
    • 2017-01-30
    • 2016-06-04
    • 2018-11-21
    • 2014-12-23
    • 1970-01-01
    • 1970-01-01
    • 2017-08-13
    • 2020-03-18
    相关资源
    最近更新 更多