Java LazyInitializationException:为什么可以';Hibernate是否在延迟加载时创建会话?

Java LazyInitializationException:为什么可以';Hibernate是否在延迟加载时创建会话?,java,hibernate,spring-boot,lazy-loading,Java,Hibernate,Spring Boot,Lazy Loading,我的项目过去到处都有@Transactional方法。现在,由于业务逻辑的原因,我不想在出现问题时回滚,而是想将我的对象设置为错误状态(aka保存在db中,因此肯定不会回滚),因此我删除了一些@Transactional来启动 现在的问题是在没有会话的情况下存在延迟加载,因此产生了LazyInitializationException 现在,以下是我目前正在寻找的故障排除和解决方案: 我们使用的是注释配置,所以这里没有xml配置 对于使用数据库的每个操作,都会创建一个EntityManager

我的项目过去到处都有@Transactional方法。现在,由于业务逻辑的原因,我不想在出现问题时回滚,而是想将我的对象设置为错误状态(aka保存在db中,因此肯定不会回滚),因此我删除了一些@Transactional来启动

现在的问题是在没有会话的情况下存在延迟加载,因此产生了LazyInitializationException

现在,以下是我目前正在寻找的故障排除和解决方案:

  • 我们使用的是注释配置,所以这里没有xml配置

  • 对于使用数据库的每个操作,都会创建一个EntityManager(在服务中定义为属性和@Autowired),然后将其删除(当添加配置以查看它们时,我可以在日志中清楚地看到它),根据Spring文档,这显然是正常的

  • 将@PersistenceContext或@PersistenceUnit与EntityManager Factory或EntityManager一起使用都不起作用

  • 我可以加载我想在Hibernate.initialize()中使用的lazy-loaded属性,这样就不会产生LazyInitializationException

现在我的问题是:为什么hibernate不能自己做呢?如果我使用延迟加载,我希望Hibernate创建一个会话(在执行Hibernate.initialize()时,他似乎完全能够这样做)来自动加载日期,这对我来说似乎微不足道

有没有办法生成一个新的实体管理器,在我的方法中使用,这样Hibernate就不会一直创建和重新创建实体管理器?我真的觉得我缺少了一些关于Hibernate、延迟加载和会话的基本信息,这些信息使整个混乱变得不那么复杂

以下是一个例子:

@Entity
@Table(name = "tata")
public class Tata {

    @Id
    @Column(name = "tata_id")
    private Long id;

    // getter / setter etc
}

@Entity
@Table(name = "toto")
public class Toto {

    @Id
    @Column(name = "toto_id")
    private Long id;

    @OneToOne(fetch = FetchType.LAZY)
    @JoinColumn(name = "tata_id")
    private Tata tata;

    // getter / setter etc
}

@Service("totoManager")
public class TotoManager extends GenericManagerImpl {

    @Autowired
    private EntityManager entityManager;
    @Autowired
    private TotoRepository totoRepository;

    public void doSomethingWithTotos() throws XDExceptionImpl {

        List<Toto> totos = this.totoRepository.findAll();

        for (toto toto : totos) {
        // LazyInitializationException here
            LOGGER.info("tata : " + toto.getTata().getId());
        }
    }
}
@实体
@表(name=“tata”)
公共级塔塔{
@身份证
@列(name=“tata\u id”)
私人长id;
//吸气剂/塞特等
}
@实体
@表(name=“toto”)
公共课托托{
@身份证
@列(name=“toto_id”)
私人长id;
@OneToOne(fetch=FetchType.LAZY)
@JoinColumn(name=“tata\u id”)
私人塔塔塔塔;
//吸气剂/塞特等
}
@服务(“totoManager”)
公共类TotoManager扩展了GenericManagerImpl{
@自动连线
私人实体管理者实体管理者;
@自动连线
私人对储蓄对储蓄;
public void doSomethingWithToToTos()抛出XDExceptionImpl{
List totos=this.totoRepository.findAll();
用于(toto toto:totos){
//LazyInitializationException在这里
LOGGER.info(“塔塔:+toto.getta().getId());
}
}
}

尝试在视图中阅读有关打开会话的内容,以了解延迟加载在会话/事务之外不起作用的原因。如果需要,可以设置属性
spring.jpa.open in view=true
,它将加载延迟加载的数据。

Hibernate可以自己完成。通过设置property
hibernate.enable_lazy\u load\u no\u trans=true
(对于spring boot,它应该是
spring.jpa.properties.hibernate.enable_lazy\u load\u no\u trans=true
),您可以在事务关闭时加载任何惰性属性。这种方法有很大的缺点:每次加载lazy属性时,hibernate都会打开会话并在后台创建事务


我建议您通过获取惰性属性。因此,您不必移动持久性上下文来执行更高级别的操作或更改实体中的获取类型。

在使用spring.jpa.open in view=trues时,我仍然存在LazyInitializationException问题。您可以将示例应用程序发布到某个地方吗?因为我不打算将公司代码放在这里,也因为它是一个相当大的代码块。我将尝试制作一个示例。用一个示例更新了我的帖子。您希望hibernate什么时候初始化会话?当我想全面访问塔塔时,因为根据定义,它没有加载,需要到达数据库才能加载。谢谢。我要看entityGraphs,但从我在日志事务和会话中看到的情况来看,他一直在创建大量的会话和entitymanager。是否有一种方法可以让他至少在短时间内维护一个会话以提高性能?在这一点上,为了避免这个问题,我将在代码中的任何地方定义事务,而不是在性能上受到影响。。。