如果按照标准的spring+hibernate的整合,当使用load加载一个实体是,会报no session的错误
这是因为,延迟加载需要在同一个session中,如果按照标签配置,session在load后就已经关闭,因此页面上显示实体属性时通过代理延迟加载便会报no session的错误了。
解决办法,spring中提供了一个OpenSessionInViewFilter的filter用来在一个http请求中保持hibernate的session
配置如下:
<filter>
</filter>
二、此时查询数据库均没问题,但是当update一个实体,会报Write operations are not allowed in read-only mode (FlushMode.NEVER) - turn your Session into 错误
这是因为,使用了OpenSessionInViewFilter后,spring会把hibernate的FlushMode改为FlushMode.NEVER,FlushMode.NEVER是不允许更新修改数据库操作的。
解决办法:
1.使用事务控制修改FlushMode
<property name="transactionAttributes">
</property>
这里不具体解释了,声明式事务的概念说起来也很多,需要注意的是HibernatTemplate的flushMode要设置为commit。
2.修改OpenSessionInViewFilter的属性,改为AUTO
<filter>
这里我们使用的是第二种方式。
三、到此查询修改操作不会再报错了,是不是已经配置好了呢?仔细一看,修改是没报错了,但是修改的结果并没有写入数据库
这是因为,spring在flush时会判断一下,请详见spring的源代码:
HibernateTemplate.doExecute{
......
flushIfNecessary(session, existingTransaction);
......
}
protected void flushIfNecessary(Session session, boolean existingTransaction) throws HibernateException {
意思就是,spring的flushmode为FLUSH_EAGER || (flushmode不是FLUSH_NEVER && 不是事务)
很遗憾使,用了OpenSessionInViewFilter后,existingTransaction=true,也就是说此时spring认为是一个事务
解决办法:
1.将HibernateTemplate的flushmode设置为FLUSH_EAGER
2.既然spring不能自动flush,咱们就自己来吧,在update()后flush()
到此,延迟加载已经可以正常使用了。
附:在调试是还遇到过这样一个错误:
a different object with the same identifier value was already associated with the session。
这是因为在session的生命周期中如果存在多个实体,hibernate不知道以哪个为准,可以用evict、clear、merg解决
@NotFound(action=NotFoundAction.IGNORE)
many-to-one加这个注释延时加载就失效