有 Java 编程相关的问题?

你可以在下面搜索框中键入要查询的问题!

java@Transactional在@Service中不工作

我正在用Jersey、Spring和Hibernate开发RESTAPI。我有一个端点:

@Path("incidences")
public class IncidencesResource {

    @InjectParam
    IncidencesService incidencesService;

    @GET
    @Produces(MediaType.APPLICATION_JSON)
    public List<Incidence> getIncidences(
            @QueryParam("lastupdate") String lastUpdate) {

        return incidencesService.getIncidences();

}

以及服务:

@Service
public class IncidencesService {

    @Autowired
    IncidencesDAO incidencesDAO;

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

}

但是我得到一个org.hibernate.LazyInitializationException错误:

Failed to lazily initialize a collection of role: com.api.blabla.Incidence.questions, no session or session was closed

questionsIncidence@OneToMany属性

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

谢谢


共 (4) 个答案

  1. # 1 楼答案

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

    我通过将@OneToMany的fetch属性更改为EAGER解决了这个问题

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

  2. # 2 楼答案

    这并不意味着@Transactional不起作用。它在做你让它做的事。该服务返回一个Incidence实例,但未初始化questions集合,您试图在服务事务之外访问该集合(可能是Jersey试图将其转换为JSON时)

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

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

    您遇到此问题是因为您的事务在服务调用时开始和结束。 回想一下Hibernate文档,惰性加载只在Hibernate会话中起作用(在本例中,Hibernate会话以服务调用开始和结束)。无法(简单地)重新连接到hibernate会话以初始化集合

    解决此问题的两种方法:

    1. 您可以将fetch类型更改为急切地加载 稍后控制器内部引用的问题

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

    此外,从更好的实践角度来看,您可能希望将服务方法中的@Transactional注释更改为@Transactional(readOnly=true),以提高只读调用的性能

  4. # 4 楼答案

    你能在这里看到什么what-does-hibernate-initialize-do

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

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