Java Spring MVC JPA延迟异常
我正在使用JPA Hibernate和Spring MVC。我已经实现了存储库模式。 我得到一个PageRepository,它只从db中获取一个页面对象。然后在控制器中,我尝试访问pageObject.getWidgets()(定义为lazy),我得到一个异常,表示会话已关闭 为了清楚起见,这里是控制器的代码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
@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修复了。对不起,我是新来的。