spring - 每次 Spring MVC Controller 返回一个 ModelAndView Hibernate fire Selects
问题描述
我有一个基于 Spring MVC 和 Hibernate 的小型 Web 应用程序。我的用户对象与宠物对象具有 oneToMany 关系:
@OneToMany(mappedBy="user", cascade=CascadeType.ALL, fetch=FetchType.EAGER)
private Set<Pet> myPets;
即使我在登录后将我的用户对象保留在 Session 中(我知道这是一种罪过),并且它包含了他的 Pets,每次调用 Controller 方法时,在它返回一个 ModelAndView 对象后,日志显示休眠触发 Selects。
例如
@RequestMapping(value = "/in_pet-see", method = RequestMethod.GET)
public ModelAndView getSee(@RequestParam("pid") Integer pId, ModelAndView model) {
User u = getUserFromSession();
if(u==null) {
u = getUser();
}
Set<Pet> pets = u.getMyPets();
Pet p = getPetFromSet(pets, pId);
model.addObject("user", u);
model.addObject("petType", petTypeMap.get(p.getType()));
model.addObject("petAttribute", p);
model.setViewName("b-see-pet");
return model;
}
private User getUserFromSession() {
return (User)session().getAttribute("user");
}
public static HttpSession session() {
ServletRequestAttributes attr = (ServletRequestAttributes) RequestContextHolder.currentRequestAttributes();
return attr.getRequest().getSession(true); // true == allow create
}
private Pet getPetFromSet(Set<Pet> set, int pId) {
Pet myPet = null;
for (Iterator<Pet> it = set.iterator(); it.hasNext(); ) {
Pet p = it.next();
if (p.getPetId()==pId) {
myPet = p;
}
System.out.println("Pet found");
}
return myPet;
}
我怎样才能避免这种情况?
笔记
我解决此问题的方法是克隆休眠对象并将克隆放入 HttpSession 中,然后在那些可以对用户或用户的依赖对象进行更改(在我的应用程序中很少见)的方法中,在这些方法的末尾调用同步方法:
/** Get a new user from DDBB, after some change and put it on Session to deliver fresh data */
private void sinchronizeUser() {
User oldSmith = getUserFromSession();
User u = myUserService.loadUserById(oldSmith.getUserId());
User smith = (User) u.clone();
session().setAttribute("user", smith);
}
解决方案
我猜这种行为是所谓的 Hibernate 脏检查机制的结果。在这里您可以了解更多信息:
https://vladmihalcea.com/the-anatomy-of-hibernate-dirty-checking/
就我而言,我终于找到了一种防止 Hibernate 选择的方法,它只是克隆 Hibernate 对象并在我的 HttpSession 中使用克隆对象。我的意思是我仍然使用 fetch eager,因为我需要预加载所有用户数据(很小)。并且使用克隆对象休眠不会触发任何更新。
推荐阅读
- c++ - 来自 DLL 函数的回调
- angular - 如何使用单击事件动态添加行并以角度自动生成 ID
- r - 如何用插入符号绘制预测机器学习?
- python-3.x - 在 Tkinter Python 中的条目小部件内设置默认插入符号位置
- qnamaker - QnA maker 从多个 kb 中获得答案
- ionic2 - 在 ionic 3 中使用后台地理位置无法将位置数据更新到服务器中
- vue.js - 如何在 gridsome 中添加和使用 vue-confetti
- java - 强制 kafka 消费者轮询具有最高延迟的分区
- reactjs - useForm 在既不是 React 函数组件的函数中被调用...错误
- sql - SQL Server:防止重复值的存储过程