我在Spring MVC控制器中使用JPA延迟加载(但它可能是一个偶然的servlet)。我发现一个Book实体与作者有@ManyToOne懒惰关系。
@Entity
public class Book extends BaseEntity {
private String isbn;
private String title;
@ManyToOne(fetch= FetchType.LAZY)
private Author author;
private int price;
SpringMVC控制器可以找到它(为了示例我简化了代码):
@Controller
public class EditBookController {
@Autowired BookDao bDao;
@RequestMapping(value={"/updatebook"})
public String updateBook(@RequestParam("id")Long id) {
Book book = bDao.find(id);
System.out.println( book.getAuthor().getFirstName() ); // Lazy loading FAIL
return “bookView”;
}
BookDao.find()在其祖先BaseRepository中定义:
@Transactional
@SuppressWarnings("unchecked")
public class BaseRepository<E extends BaseEntity> {
Class entityClass;
public E find(Long id){
return ( E ) em.find( entityClass, id );
}
当然它会在控制器中触发LazyInit异常。所以我添加了过滤器OpenEntityManagerInViewFilter并且它工作正常:书籍实体在控制器中不再分离。
现在,我想在控制器中修改这本书。例如,我调用book.setPrice(4);
@RequestMapping(value={"/updatebook"})
public String updateBook(@RequestParam("id")Long id) {
Book book = bDao.find(id);
System.out.println( book.getAuthor().getFirstName() ); // Lazy loading OK
book.setPrice(4);
return “bookView”;
}
我希望Hibernate能够进行脏检查,检测到该书的值已被更改并保存。关闭EntityMangager时,它将由OpenEntityInViewFilter触发。
但我的(非分离的)托管实体不会触发对DB的更新,除非我明确地调用em.merge(book)。
有人可以向我解释为什么在这种情况下脏检查不活跃? 非常感谢!
Spring v3.1.2 Hibernate v4.1.4
答案 0 :(得分:0)
您在使用什么来管理交易?
如果spring正在管理它们,那么您需要在控制器方法中添加@Transactional。 @Transactional注释用于划分事务开始的位置,因此您遇到的问题是spring / hibernate不知道在updateBook()
返回时需要保留任何更改。 OpenEntityManagerInViewFilter不提交事务(但您可能希望编写自己的提交实现)。
在我看来(其他人可能不同意),使用@Transactional注释应用程序的入口点是一个好习惯,它们可能是控制器,JMS使用者或其他任何东西。