LazyInitializationException:为什么Hibernate无法在延迟加载时创建会话?

时间:2019-03-20 13:55:31

标签: java hibernate spring-boot lazy-loading

我的项目中到处都有很多@Transactional方法。现在由于业务逻辑,我不想在遇到问题时回滚,而是想将对象设置为错误状态(又名保存在数据库中,因此绝对不会回滚),因此我删除了一些@Transactional来启动。

现在的问题是,那里存在延迟加载,没有会话,因此产生了LazyInitializationException。

现在这是我到目前为止的以下故障排除和解决方案:

  • 我们正在使用注释配置,因此此处没有xml配置。

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

  • 在EntityManagerFactory或EntityManager上使用@PersistenceContext或@PersistenceUnit不起作用。

  • 可以加载我想与Hibernate.initialize()一起使用的延迟加载属性,然后它不会产生LazyInitializationException。

现在我的问题是:为什么冬眠不能自己做呢?在我看来,如果我使用的是延迟加载,我想让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());
        }
    }
}

2 个答案:

答案 0 :(得分:1)

尝试阅读一些有关打开会话的视图的信息,以了解为什么延迟加载在会话/事务之外无法正常工作的原因。如果需要,可以设置属性spring.jpa.open-in-view=true,它将加载您的延迟加载数据。

答案 1 :(得分:0)

Hibernate可以自己完成。使用设置属性hibernate.enable_lazy_load_no_trans=true(对于春季启动,它应为spring.jpa.properties.hibernate.enable_lazy_load_no_trans=true),您可以在事务关闭时加载任何惰性属性。这种方法有一个很大的缺点:每次加载惰性属性时,休眠都会打开会话并在后台创建事务。

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