【问题标题】:@Transactional is not working in @Service@Transactional 在 @Service 中不起作用
【发布时间】:2015-07-22 09:29:51
【问题描述】:

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

@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 错误:

延迟初始化角色集合失败: com.api.blabla.Incidence.questions,没有 会话或会话已关闭

questionsIncidence@OneToMany 属性。

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

谢谢。

【问题讨论】:

  • 异常在哪里抛出,在哪个类? Incidence 何时转换为 JSON?
  • 如果在服务方法中返回incidences 之前调用Hibernate.initialize(incidences.getQuestions()) 怎么办?另一种解决方案是急切地而不是懒惰地获取questions,可以使用@OneToManyfetch 属性进行配置。
  • 请写入spring设置xml文件。

标签: java spring hibernate


【解决方案1】:

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

在这种情况下,服务必须返回调用者需要的所有数据,这意味着你必须在返回结果之前初始化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;
}

【讨论】:

  • 我遇到了同样的错误。 initialize 到底是什么意思?我已经逐步调试,当我检索一个事件时,我正在检索嵌套问题,因为这是一对多的关系。
  • Hibernate.initialize() 将初始化延迟获取的对象,@OneToMany 默认为延迟获取。你得到完全相同的例外吗?你可以发布堆栈跟踪吗?应该对所有转换为 JSON 的关系执行此操作,也许其他一些关系导致异常?
【解决方案2】:

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

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

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

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

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

【讨论】:

    【解决方案3】:

    你可以在这里看到什么初始化what-does-hibernate-initialize-do

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

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

    【讨论】:

      【解决方案4】:

      解决了!我在 LAZY 获取类型(默认)中有Incidence -&gt; questions 关系。但是,在端点资源方法中,我调用了getQuestions()。这段代码不在事务中,所以它抛出了初始化异常。

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

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

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2015-04-02
        • 1970-01-01
        • 2019-04-26
        • 2012-04-18
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多