我的项目中到处都有很多@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());
}
}
}
答案 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获取懒惰的属性。因此,您不必移动持久性上下文来进行高层操作或更改实体中的提取类型。