LazyInitializationException:为什么 Hibernate 不能在延迟加载时创建会话?
LazyInitializationException : Why can't Hibernate create a session on lazy loading?
我的项目过去到处都有很多@Transactional 方法。现在由于业务逻辑,我不想在遇到问题时回滚,而是想将我的对象设置为错误状态(也就是保存在数据库中,所以绝对不会回滚),所以我删除了一些 @Transactional 以开始。
现在的问题是有延迟加载的地方没有会话,因此产生了 LazyInitializationException。
下面是我目前为止的以下故障排除和解决方案:
我们使用的是注释配置,所以这里没有xml配置。
对于使用数据库的每个操作,都会创建一个 EntityManager(在服务中定义为属性和@Autowired),然后将其删除(添加配置时我可以在日志中清楚地看到它看到它们),根据 Spring 文档,这显然是正常的。
将@PersistenceContext 或@PersistenceUnit 与 EntityManagerFactory 或 EntityManager 一起使用都不起作用。
我 可以 加载我想与 Hibernate.initialize() 一起使用的延迟加载属性,然后它不会产生 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());
}
}
}
尝试阅读有关 在视图中打开会话 的内容,以了解为什么 延迟加载 在 session/transaction 中不起作用。如果你愿意,你可以设置 属性 spring.jpa.open-in-view=true
它会加载你的延迟加载数据。
Hibernate 可以自己完成。通过设置 属性 hibernate.enable_lazy_load_no_trans=true
(对于 spring 引导,它应该是 spring.jpa.properties.hibernate.enable_lazy_load_no_trans=true
),您可以在事务关闭时加载任何惰性 属性。这种方法有一个很大的缺点:每次你加载延迟 属性,hibernate 打开会话并在后台创建事务。
我建议 entityGraphs 获取惰性属性。因此,您不必将持久上下文移动到更高级别或更改实体中的获取类型。
我的项目过去到处都有很多@Transactional 方法。现在由于业务逻辑,我不想在遇到问题时回滚,而是想将我的对象设置为错误状态(也就是保存在数据库中,所以绝对不会回滚),所以我删除了一些 @Transactional 以开始。
现在的问题是有延迟加载的地方没有会话,因此产生了 LazyInitializationException。
下面是我目前为止的以下故障排除和解决方案:
我们使用的是注释配置,所以这里没有xml配置。
对于使用数据库的每个操作,都会创建一个 EntityManager(在服务中定义为属性和@Autowired),然后将其删除(添加配置时我可以在日志中清楚地看到它看到它们),根据 Spring 文档,这显然是正常的。
将@PersistenceContext 或@PersistenceUnit 与 EntityManagerFactory 或 EntityManager 一起使用都不起作用。
我 可以 加载我想与 Hibernate.initialize() 一起使用的延迟加载属性,然后它不会产生 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());
}
}
}
尝试阅读有关 在视图中打开会话 的内容,以了解为什么 延迟加载 在 session/transaction 中不起作用。如果你愿意,你可以设置 属性 spring.jpa.open-in-view=true
它会加载你的延迟加载数据。
Hibernate 可以自己完成。通过设置 属性 hibernate.enable_lazy_load_no_trans=true
(对于 spring 引导,它应该是 spring.jpa.properties.hibernate.enable_lazy_load_no_trans=true
),您可以在事务关闭时加载任何惰性 属性。这种方法有一个很大的缺点:每次你加载延迟 属性,hibernate 打开会话并在后台创建事务。
我建议 entityGraphs 获取惰性属性。因此,您不必将持久上下文移动到更高级别或更改实体中的获取类型。