今天接到测试反馈的一个bug,他在系统上点击详情页面的时候,关掉详情页面,然后再点击一次进入详情页面,发现页面中有两个字段的值被更改了。我检查后发现是由于有个新来的同事不够细心引起的bug。代码如下所示
/**
* add ljk 20160822
* @return
* @throws Exception
*/
public String toView() throws Exception{
String clueId=request.getParameter("clueId");
ClueInfo entity = new ClueInfo();
ClueInfo clueInfo=clueInfoService.findById(clueId);
//避免clueInfo执行更新操作
BeanUtils.copyProperties(clueInfo, entity);
SystemDictionary ldqk=systemDictionaryService.findById(entity.getLuoDiQingKuang());
SystemDictionary czqk=systemDictionaryService.findById(entity.getChuzhi_qingkuang());
if(null!=ldqk){
entity.setLuoDiQingKuang(ldqk.getInfo());
}else{
entity.setLuoDiQingKuang("");
}
if(null!=czqk){
entity.setChuzhi_qingkuang(czqk.getInfo());
}else{
entity.setChuzhi_qingkuang("");
}
@SuppressWarnings("unchecked")
List<Map<String,Object>> receiveUserList = clueInfoReceiveUserService.findReceiveUserNameByClueId(clueId);
新来的同事可能不太熟悉hibernate的一些特性,hibernate查询返回实体后,如果不希望对实体执行更新操作,就不应该更改实体里的属性值,否则如果更改实体属性值后,然后接着执行对数据库的任何操作,hibernate都会触发对实体的更新操作。在上面的代码片段中可以看出,实体的两个属性值被更改了: entity.setLuoDiQingKuang(ldqk.getInfo());
entity.setChuzhi_qingkuang(czqk.getInfo());
任何后面又执行了一条查询语句:
clueInfoReceiveUserService.findReceiveUserNameByClueId(clueId);
所以ClueInfo 里面的两个属性值就被更新了。这里新手很容易掉进这个坑里,而且会感到莫名其妙,我以前刚学hibernate的时候也碰到过这种问题,一步一步debug进去发现在执行完某条查询语句之后后台打印出了更新的sql语句。但是明明自己没有调用任何更新的接口。
这里顺便提一下hibernate的get和load的区别:
1、get()和load()都会使用缓存,都是首先从一级缓存Session中查找,当找不到的时候再去二级缓存中查找,当查询不到的时候get()返回的是null,而load()则返回代理对象。
2、get()在调用的时候就立即发出SQL语句查询。
3、load()利用到了延时加载机制,而且返回的是一个代理对象,只有当访问到了代理对象的非ID属性时才会发出SQL语句查询。
4、load()查询不到数据返回的是代理对象,然后当我们使用代理对象qu去访问被代 理对象时由于找不到真实的对象而抛出ObjectNotFoundException异常。
如果在load()在缓存中能找到数据,则返回真实的对象而不是代理对象。
5、load()返回的代理对象依赖产生这个代理对象的那个Session,如果这个Session被关闭后还要访问这个代理对象,会抛出LazyInitializationException异常。