Java Spring MVC JPA延迟异常

Java Spring MVC JPA延迟异常,java,hibernate,jpa,spring-mvc,Java,Hibernate,Jpa,Spring Mvc,我正在使用JPA Hibernate和Spring MVC。我已经实现了存储库模式。 我得到一个PageRepository,它只从db中获取一个页面对象。然后在控制器中,我尝试访问pageObject.getWidgets()(定义为lazy),我得到一个异常,表示会话已关闭 为了清楚起见,这里是控制器的代码 @RequestMapping(value = "/pages/get",method=RequestMethod.GET) public @ResponseBody Strin

我正在使用JPA Hibernate和Spring MVC。我已经实现了存储库模式。 我得到一个PageRepository,它只从db中获取一个页面对象。然后在控制器中,我尝试访问pageObject.getWidgets()(定义为lazy),我得到一个异常,表示会话已关闭

为了清楚起见,这里是控制器的代码

@RequestMapping(value = "/pages/get",method=RequestMethod.GET)
    public @ResponseBody String getPage(@RequestParam Long id){
        .....
            Page page = pageRepository.getById(id);
            if(page!=null && page.getWidgets()!=null){
                for(Widget widget: page.getWidgets()){ <--- here the exception occurs
                    ....    }
@RequestMapping(value = "/pages/get",method=RequestMethod.GET)
    public @ResponseBody String getPage(@RequestParam Long id){
        return new Gson().toJson(new ActionResult(pageBuilderService.buildAdapterFromPage(id)));
    }
那么,我能做些什么来解决这个问题呢


提前感谢

我们没有使用纯JPA,而是通过Hibernate使用JPA,为了让延迟加载发挥作用,您需要在方法上添加@Transactional注释。这将导致连接在方法的生存期内保持打开状态


控制器方法不会被外部调用,因此不受@Transactional所依赖的代理的约束。可能必须将实体图遍历代码移动到“服务”类中,并在其中应用@Transactional。

没有使用纯JPA,而是通过Hibernate使用JPA,为了使延迟加载正常工作,您需要在方法上添加@Transactional注释。这将导致连接在方法的生存期内保持打开状态


控制器方法不会被外部调用,因此不受@Transactional所依赖的代理的约束。可能必须将实体图遍历代码移动到“服务”类中,并在其中应用@Transactional。

多亏了all。我解决了在组件或服务中编写代码的问题。因此,我可以毫无问题地使用@Transactional

这是密码

方法控制器

@RequestMapping(value = "/pages/get",method=RequestMethod.GET)
    public @ResponseBody String getPage(@RequestParam Long id){
        .....
            Page page = pageRepository.getById(id);
            if(page!=null && page.getWidgets()!=null){
                for(Widget widget: page.getWidgets()){ <--- here the exception occurs
                    ....    }
@RequestMapping(value = "/pages/get",method=RequestMethod.GET)
    public @ResponseBody String getPage(@RequestParam Long id){
        return new Gson().toJson(new ActionResult(pageBuilderService.buildAdapterFromPage(id)));
    }
服务

@Component(value="PageBuilderService")
public class PageBuilderService {

    @Autowired
    private IPageRepository pageRepository;


    public void setPageRepository(IPageRepository pageRepository) {
        this.pageRepository = pageRepository;
    }

    @Transactional
    public List<WidgetAdapter> buildAdapterFromPage(Long pageId){
        List<WidgetAdapter> adapters = new ArrayList<WidgetAdapter>();
        if(pageId!=null){
            Page page = pageRepository.getById(pageId);
            if(page!=null && page.getWidgets()!=null){
                for(Widget widget: page.getWidgets()){
                    adapters.add(WidgetFactory.FactoryMethodAdapter(widget));
                }
            }
        }
        return adapters;
    }

}
组件(value=“PageBuilderService”) 公共类PageBuilderService{ @自动连线 私有IPageRepository页面存储库; public void setPageRepository(IPageRepository页面存储库){ this.pageRepository=pageRepository; } @交易的 公共列表生成器适配器跳转页面(长页面ID){ List adapters=new ArrayList(); if(pageId!=null){ Page=pageRepository.getById(pageId); if(page!=null&&page.getWidgets()!=null){ for(小部件:page.getWidgets()){ add(WidgetFactory.FactoryMethodAdapter(小部件)); } } } 返回适配器; } }
这就是我从提供的信息中得到的解决方案。我不知道这是否是最好的,但我认为这是一个很好的解决方案。

谢谢大家。我解决了在组件或服务中编写代码的问题。因此,我可以毫无问题地使用@Transactional

这是密码

方法控制器

@RequestMapping(value = "/pages/get",method=RequestMethod.GET)
    public @ResponseBody String getPage(@RequestParam Long id){
        .....
            Page page = pageRepository.getById(id);
            if(page!=null && page.getWidgets()!=null){
                for(Widget widget: page.getWidgets()){ <--- here the exception occurs
                    ....    }
@RequestMapping(value = "/pages/get",method=RequestMethod.GET)
    public @ResponseBody String getPage(@RequestParam Long id){
        return new Gson().toJson(new ActionResult(pageBuilderService.buildAdapterFromPage(id)));
    }
服务

@Component(value="PageBuilderService")
public class PageBuilderService {

    @Autowired
    private IPageRepository pageRepository;


    public void setPageRepository(IPageRepository pageRepository) {
        this.pageRepository = pageRepository;
    }

    @Transactional
    public List<WidgetAdapter> buildAdapterFromPage(Long pageId){
        List<WidgetAdapter> adapters = new ArrayList<WidgetAdapter>();
        if(pageId!=null){
            Page page = pageRepository.getById(pageId);
            if(page!=null && page.getWidgets()!=null){
                for(Widget widget: page.getWidgets()){
                    adapters.add(WidgetFactory.FactoryMethodAdapter(widget));
                }
            }
        }
        return adapters;
    }

}
组件(value=“PageBuilderService”) 公共类PageBuilderService{ @自动连线 私有IPageRepository页面存储库; public void setPageRepository(IPageRepository页面存储库){ this.pageRepository=pageRepository; } @交易的 公共列表生成器适配器跳转页面(长页面ID){ List adapters=new ArrayList(); if(pageId!=null){ Page=pageRepository.getById(pageId); if(page!=null&&page.getWidgets()!=null){ for(小部件:page.getWidgets()){ add(WidgetFactory.FactoryMethodAdapter(小部件)); } } } 返回适配器; } }
这就是我从提供的信息中得到的解决方案。我不知道这是否是最好的,但我认为这是一个很好的解决方案。

如果我这样做,我会得到以下异常:无法代理目标类,因为CGLIB2不可用。将CGLIB添加到类路径或指定代理接口。。你必须向你的控制器类中添加一个无参数构造函数。我按照你的建议做了,但我仍然无法懒洋洋地初始化一组角色:com.Page.widgets,没有会话或会话关闭。你可以将
OpenEntityManagerInViewFilter
添加到web.xmlOk,最后一条建议:我在别处读到Spring不会代理到事务所需的控制器类。我个人将所有事务放在“服务”类的一层中,这就是我应用@Transactional而不是控制器的地方。也许你可以试一试。如果我这样做,我会得到以下异常无法代理目标类,因为CGLIB2不可用。将CGLIB添加到类路径或指定代理接口。。你必须向你的控制器类中添加一个无参数构造函数。我按照你的建议做了,但我仍然无法懒洋洋地初始化一组角色:com.Page.widgets,没有会话或会话关闭。你可以将
OpenEntityManagerInViewFilter
添加到web.xmlOk,最后一条建议:我在别处读到Spring不会代理到事务所需的控制器类。我个人将所有事务放在“服务”类的一层中,这就是我应用@Transactional而不是控制器的地方。也许你可以试一试。好吧,所以我不辞辛劳地帮你让它工作,而你为自己的答案感到自豪。很好。@musli BTW for service class存在特殊的注释
@service
,这对您来说会更好。@splonk i修复了。很抱歉,我是新来的。好吧,所以我不辞辛劳地帮你让它工作,你给自己的答案。很好。@musli BTW for service class存在特殊的注释
@service
,这对您来说会更好。@splonk i修复了。对不起,我是新来的。