hibernate 事务拦截器和struts action chain的一个诡异问题
描述:
在页面使用struts的list集合去做一些输入框,然后保存展示。发现保存之后总是不对。
以下为寻找问题的步骤:
首先怀疑是不是hibernate配置的有问题。
看了文章,然后也根据项目另外一个地方使用的地方对比然后更改,确定了不是配置的问题。在父类中配置inverse=”false” cascade=”all” 是ok的。inverse只是和save的方式有关。怀疑是不是hibernate的写法有问题。
看网上的文章都是parent.getChildren().add(e)。然后更改成这样也不行。看console中打印的语句,最后发现了一个问题,就是在本来save Action调用结束后,结果是正常的(通过数据库中查询出来观察)。但是进入到一个页面的时候,一个无关的可以开启事务的方法(称为A)执行之后,也提交了一个update方法,很诡异的是A这个方法和update的对象完全无关,upate完成之后原来的正确数据就丢失了。
通过多次debug的单步执行,找到了具体发出update语句的位置。然后观察Action的变量发现了问题。
假设我们传进后台的Form成为saveForm,然后其中有一个list(成为recordList)是我们多条记录的结果。
saveForm传入到后台之后,我在代码之中不光使用了,而且有修改recordList,之后set给了saveForm。在save Action执行结束的时候,这个form是正常的。但执行结束之后,这个saveForm就不正常了。recordList其中有一个带上了hibernate自生成的主键和外键,然后事务拦截器在第二个action退出service的方法时候,就提交了这个非游离态的对象,形成了update语句。
这里有点没有确实的说明:
- action chain的时候,参数如果我们修改了是在下一个action中会变成怎样。在Struts官方文档中说chainingInterceptor会进行拷贝,但是现在的结果证明还有merge的效果。只是推断,如果知道请直接留言指点我一下,谢谢。
解决方法:
- 在chainInterceptor的时候加上过滤,哪些对象进行chain。注意是在拦截器上加,不是在chain的result中加。
- 继承Unchainable接口。(尝试了,让form这个dto继承接口,没有效果)
- 在save Action结束的时候,将form置成null。但是你会发现下一个action的时候还有form,只不过缺少了merge效果,是最初的form内容了。(struts转发的是上一个action的interceptor信息和action结果)
- 将chain换成redirect方法。
结语:
花了好长时间来定位错误,最初以为代码中藏了什么东西。在使用Struts chain的时候还要注意,不要与已经非游离态的对象产生互相影响,或者不去修改interceptor中的内容,只是使用。