前面提到的,spring下hibernate的Hibernate.initialize(Objct o)是无效的,在我自己的测试中,我是使用了类似....getSet().size()的方法,强制加载集合类属性.google之后,知道,还可以通过Hibernate.initialize(o.getSet())的方式,强制加载.
另一种方式解决懒加载问题是使用OpenSessionInView,让事务边界扩到到一次请求,使用这种方式需要在web.xml中设置Filter或Listener。但考虑到扩大事务边界,会增加Session打开的时间,相应的会增加资源的开销,当并发数量多的时候,性能会下降,因此,我并不打算使用。会使用了在find()的方法中强制加载。当然,实际上可以写一个方法,在方法中增加一个控制是否要强制加载的参数!
前面还提到,当只提交了表单之后,会有多余的delete语句。前面说到的一些内容,理解上可能有偏差。我单独写了一个测试单元,进行了测试:
使用find()找到的board,即使懒加载没有强制查找值,不会出现delete,但如果不是find()的,而是new一个新的board,指定一个已存在id的情况下,才会出现delete。
当action的scope是prototype时,每次提交更新,都是new一个board,而不是find()相应的值,所以会有delete 语句。解决的办法很简单,在BoardAction的相应方法中,首先find()出相应id的board,然后,根据表单提交的内容变更相应的值,最后使用Service层的update方法。
是否会产生多余的delete与是否懒加载是无关的。使用find()找出的对象,hibernate会跟踪它的值是否有变化。无论懒加载的是Set类型的属性还是一般类型的属性,只要没有变更过它们的值,hibernate都不会有相应的更新操作。
在前面提到过的实验中,当BoardAction的scope是单例模式下,当第一次执行过find()方法之后,无论之后提交多少次表单,boardAction中的成员变量board,同是同一个board,每次提交表单仅仅是变更提交的那些属性的内容,其他内容没有任何操作,如(管理员,managers,虽然是懒加载,也没有值,但是并没有对它进行操作),因此,当执行更新时不会有多余的delete.
update与merge的区别:update无论是否变更都执行update语句,merger会先执行一条select,然后看是否有变更,有的话再执行update语句。
BoardAction 代码片段:
public String update() throws Exception{
Board b = boardService.find(Board.class,board.getId());
b.setIndex(board.getIndex());
b.setName(board.getName());
b.setDescribe(board.getDescribe());
b.setVisible(board.isVisible());
boardService.update(b);
return "success";
}