【问题标题】:LazyInitializationException : Why can't Hibernate create a session on lazy loading?LazyInitializationException : 为什么 Hibernate 不能在延迟加载时创建会话?
【发布时间】:2019-03-20 13:55:31
【问题描述】:

我的项目曾经到处都有很多@Transactional 方法。现在由于业务逻辑,我不想在遇到问题时回滚,而是想将我的对象设置为错误状态(也就是保存在数据库中,所以绝对不是回滚),所以我删除了一些 @Transactional 开始。

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

下面是我目前的故障排除和解决方案:

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

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

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

  • 我可以加载我想与 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());
        }
    }
}

【问题讨论】:

  • 您希望休眠何时初始化会话?
  • 当我想完全访问 tata 时,因为根据定义它没有加载,它需要到达数据库来加载它

标签: java hibernate spring-boot lazy-loading


【解决方案1】:

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

我建议通过entityGraphs 获取惰性属性。因此,您不必将持久上下文移动到上层或更改实体中的获取类型。

【讨论】:

  • 这行得通,谢谢。我将研究 entityGraphs,但从我从记录事务和会话中看到的情况来看,他一直在创建大量的会话和实体管理器。为了性能起见,有没有办法让他至少在短时间内保持会话?在这一点上,我将通过在代码中随处定义事务来避免该问题...
【解决方案2】:

尝试阅读有关 Open session in view 的内容,以了解为什么 延迟加载 在会话/事务之外不起作用。如果你愿意,你可以设置属性spring.jpa.open-in-view=true,它会加载你延迟加载的数据。

【讨论】:

  • 我在使用 spring.jpa.open-in-view=true 时仍然遇到 LazyInitializationException
  • 您可以在某处发布示例应用程序吗?
  • 真的不能这样做,因为我不打算把公司代码放在这里,也因为它是一个相当大的代码块。我将尝试制作一个示例。
  • 用一个例子更新了我的帖子
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2022-01-22
  • 1970-01-01
  • 1970-01-01
  • 2011-01-12
  • 1970-01-01
相关资源
最近更新 更多