我有一个控制器,我在更新实体之前通过验证器验证ModelAttribute,如下面的代码所示。验证器在obj变量中接收要更新的对象。
我遇到的问题是当我运行这个方法restaurantRepository.findByEmail时,validate方法中的修改对象(obj)被保存到数据库中。它与@Transactional有关。我不明白为什么它会保存obj,我还没有将它传递给方法。
我已阅读此SO帖子 Why does @Transactional save automatically to database 答案是
在事务方法即将返回之前,事务提交,这意味着对托管实体的所有更改都将刷新到数据库。
但据我所知,托管实体是@Transactional范围内的实体。我没有通过obj进入方法,所以我不明白为什么它会自动保存。
餐厅
@Entity
@Table(name="restaurant")
@SequenceGenerator(name="restaurant_seq", sequenceName="restaurant_seq")
public class Restaurant{
private String name;
private String email;
private String phonenumber;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getEmail() {
return email;
}
public void setEmail(String email) {
this.email = email;
}
public String getPhonenumber() {
return phonenumber;
}
public void setPhonenumber(String phonenumber) {
this.phonenumber = phonenumber;
}
}
RestaurantContoller
@RequestMapping("/restaurant")
@Controller
public class RestaurantController {
@Autowired
private RestaurantService restaurantRepository;
@Autowired
private RestaurantValidator restaurantValidator;
@InitBinder
protected void initBinder(WebDataBinder binder) {
binder.setValidator(restaurantValidator);
}
@GetMapping("/{id}")
public String viewRestaurant(@PathVariable("id") Long restaurant_id, final ModelMap model) {
Restaurant restaurant = restaurantService.findById(restaurant_id);
if(!model.containsAttribute("restaurantModel")){
model.addAttribute("restaurantModel", restaurant );
}
return "pages/restaurant_view_new";
}
@PatchMapping("/{restaurantModel}")
public String updateRestaurant(@Valid @ModelAttribute("restaurantModel") Restaurant editRestaurant, BindingResult bindingResult, final ModelMap model, RedirectAttributes redirectAttributes) {
if (bindingResult.hasErrors()) {
redirectAttributes.addFlashAttribute("org.springframework.validation.BindingResult.restaurantModel", bindingResult);
redirectAttributes.addFlashAttribute("restaurantModel", editRestaurant);
redirectAttributes.addFlashAttribute("saveErrors", true);
return "redirect:/restaurant/" + editRestaurant.getId();
}
restaurantRepository.save(editRestaurant);
redirectAttributes.addFlashAttribute("saveSuccess", true);
return "redirect:/restaurant/" + editRestaurant.getId();
}
}
RestaurantValidator
@Component
public class RestaurantValidator implements Validator {
@Autowired
RestaurantRepository restaurantRepository;
public boolean supports(Class clazz) {
return Restaurant.class.equals(clazz);
}
public void validate(Object obj, Errors e) {
ValidationUtils.rejectIfEmpty(e, "name", "form.required");
ValidationUtils.rejectIfEmpty(e, "email", "form.required");
ValidationUtils.rejectIfEmpty(e, "phonenumber", "form.required");
Restaurant p = (Restaurant) obj;
if(restaurantRepository.findByEmail(p.getEmail()).size() > 0 ){
e.rejectValue("email", "form.email.duplicate");
}
}
}
RestaurantRepository
@Transactional
public interface RestaurantRepository extends JpaRepository<Restaurant, Long>{
List<Restaurant> findByEmail(String email);
}
答案 0 :(得分:0)
根据我的经验,当您调用一个SELECT语句,该语句涉及在持久化上下文中查询已修改实体的数据库表时,会触发刷新。
我认为这样做的原因是Hibernate说&#34;你正在桌子上做一个选择,可能包括我在这里的未刷新实体,然后我可能会对两者中哪一个最有冲突电流&#34;
我不知道这是否与特定的FLUSH策略有关。
答案 1 :(得分:0)
问题是缺少一些细节,但我的假设是obj处于持久状态。
查看更多详情here。
因此,在提交事务时,任何修改都会自动与数据库同步。
如果您不想进行同步修改,则需要在修改对象之前将其分离
见
EntityManager.detach(Object var)
EntityManager.persits(Object var)
在您上次发表评论后,我建议您阅读以下内容Why is Hibernate Open Session in View considered a bad practice?