简体   繁体   English

@Transactional在@Service中不起作用

[英]@Transactional is not working in @Service

I'm developing a REST API with Jersey, Spring and Hibernate. 我正在使用Jersey,Spring和Hibernate开发REST API。 I have this endpoint: 我有这个端点:

@Path("incidences")
public class IncidencesResource {

    @InjectParam
    IncidencesService incidencesService;

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

        return incidencesService.getIncidences();

}

and the service: 和服务:

@Service
public class IncidencesService {

    @Autowired
    IncidencesDAO incidencesDAO;

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

}

But I get a org.hibernate.LazyInitializationException error: 但我得到一个org.hibernate.LazyInitializationException错误:

Failed to lazily initialize a collection of role: com.api.blabla.Incidence.questions, no session or session was closed 无法懒惰地初始化角色集合:com.api.blabla.Incidence.questions,没有会话或会话被关闭

questions is a @OneToMany property of Incidence . questions@OneToMany财产Incidence

If I put @Transactional annotation in the endpoint method, instead of in the service, it works properly. 如果我在端点方法中放置@Transactional注释,而不是在服务中,它可以正常工作。 But I understand that @Transactional has to be placed at service level. 但我知道@Transactional必须放在服务级别。

Thanks. 谢谢。

This does not mean @Transactional is not working. 这并不意味着@Transactional不起作用。 It is doing what you told it to do. 它正在做你告诉它要做的事情。 The service returns an instance of Incidence without initialized collection of questions , and you are trying to access that collection outside of service's transaction (probably when Jersey tries to convert it to JSON). 该服务返回一个Incidence实例而没有初始化的questions集合,并且您试图在服务的事务之外访问该集合(可能是在Jersey尝试将其转换为JSON时)。

In this situation, the service must return all the data needed by the caller, which means you have to initialize questions before returning the result. 在这种情况下,服务必须返回调用者所需的所有数据,这意味着您必须在返回结果之前初始化questions So, just call Hibernate.initialize(incidence.getQuestions()) in service method for every instance you return. 因此,只需在服务方法中为您返回的每个实例调用Hibernate.initialize(incidence.getQuestions())

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

You are having this problem because your transaction begins and ends at your service call. 您遇到此问题是因为您的交易在您的服务电话上开始和结束。 Recall from Hibernate documentation that lazy loading only works within a Hibernate Session (in this case, the hibernate session begins and ends with your service call). 回想一下Hibernate文档,延迟加载仅适用于Hibernate会话(在这种情况下,hibernate会话以服务调用开始和结束)。 You can't reconnect to the hibernate session (simply) to initialize the collection. 您无法重新连接到hibernate会话(简单地)来初始化集合。

Two approach to solve this: 解决这个问题的两种方法:

  1. You can either change the fetch type to EAGER to eagerly load the questions referenced inside the controller later 您可以将获取类型更改为EAGER,以便以后急切加载控制器内引用的问题

  2. Make a separate query to the service to get the questions for the incidence from the controller and set the response in the view bean before returning the response 对服务进行单独查询以从控制器获取有关事件的问题,并在返回响应之前在视图bean中设置响应

Additionally as suggestion from a better practise perspective you may want to change the @Transactional annotation in the service method to @Transactional(readOnly = true) for a better performance of the read only call. 此外,作为更好的实践观点的建议,您可能希望将服务方法中的@Transactional注释更改为@Transactional(readOnly = true),以便更好地执行只读调用。

What initialize does can you see here what-does-hibernate-initialize-do 什么初始化可以在这里看到什么做hibernate-initialize-do

Maybe you have to manually initialize it. 也许你必须手动初始化它。 Please try this: 请试试这个:

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

  return incidencias;
}

Solved! 解决了! I had Incidence -> questions relationship in LAZY fetch type (default). 我在LAZY获取类型中有Incidence -> questions关系(默认)。 However, in the endpoint resource method I was calling getQuestions() . 但是,在端点资源方法中,我调用了getQuestions() This code wasn't inside the transaction, so it throwed initialization exception. 此代码不在事务内部,因此它抛出了初始化异常。

I have solved it by changing fetch property of @OneToMany to EAGER . 我通过将@OneToMany fetch属性@OneToManyEAGER来解决它。

Thanks for your answers. 谢谢你的回答。 It was difficult for you to help me if you can't see the rest of the code... 如果你看不到剩下的代码,你很难帮助我...

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM