@Transactional在@Service中不起作用

时间:2015-07-22 09:29:51

标签: java spring hibernate

我正在使用Jersey,Spring和Hibernate开发REST API。我有这个端点:

@Service
public class IncidencesService {

    @Autowired
    IncidencesDAO incidencesDAO;

    @Transactional
    public List<Incidence> getIncidences() {
        List<Incidence> incidencias = incidencesDao.getIncidences();
        return incidences;
    }

}

和服务:

org.hibernate.LazyInitializationException

但我收到questions错误:

  

无法懒惰地初始化角色集合:   com.api.blabla.Incidence.questions,no   会议或会议已经结束

@OneToManyIncidence的{​​{1}}属性。

如果我在端点方法中放置@Transactional注释,而不是在服务中,它可以正常工作。但我知道@Transactional必须放在服务级别。

感谢。

4 个答案:

答案 0 :(得分:4)

这并不意味着@Transactional无效。它正在做你告诉它要做的事情。该服务返回Incidence的实例而没有初始化的questions集合,并且您尝试在服务的事务之外访问该集合(可能是在Jersey试图将其转换为JSON时)。 / p>

在这种情况下,服务必须返回调用者所需的所有数据,这意味着您必须在返回结果之前初始化questions。因此,只需在服务方法中为您返回的每个实例调用Hibernate.initialize(incidence.getQuestions())

@Transactional
public List<Incidence> getIncidences() {
    List<Incidence> incidencias = incidencesDao.getIncidences();
    for (Incidence inc : incidencias) {
        Hibernate.initialize(inc.getQuestions());
    }
    return incidencias;
}

答案 1 :(得分:1)

您遇到此问题是因为您的交易在您的服务电话中开始和结束。 回想一下Hibernate文档,延迟加载仅适用于Hibernate会话(在这种情况下,hibernate会话以服务调用开始和结束)。您无法重新连接到hibernate会话(简单地)来初始化集合。

解决这个问题的两种方法:

  1. 您可以将获取类型更改为EAGER以急切加载 稍后在控制器内引用的问题

  2. 对服务进行单独查询以从控制器获取有关事件的问题,并在返回响应之前在视图bean中设置响应

  3. 此外,根据更好的实践观点,您可能希望将服务方法中的@Transactional注释更改为@Transactional(readOnly = true),以便更好地执行只读调用。

答案 2 :(得分:0)

您可以在此处看到初始化内容what-does-hibernate-initialize-do

也许您必须手动初始化它。请试试这个:

@Transactional
public List<Incidence> getIncidences() {
  List<Incidence> incidencias = incidencesDao.getIncidences();
  for (Incidence inc : incidencias) {
    inc.getQuestions().size();
  }

  return incidencias;
}

答案 3 :(得分:0)

解决!我在 LAZY 获取类型(默认)中有Incidence -> questions个关系。但是,在端点资源方法中,我调用了getQuestions()。此代码不在事务内部,因此它抛出了初始化异常。

我已将@OneToMany的抓取属性更改为 EAGER ,从而解决了这个问题。

感谢您的回答。如果你看不到剩下的代码,你很难帮助我......