日期:2014-05-18  浏览次数:20750 次

hibernatetemplate下的saveOrUpdate的实际效果和说明为啥不一样?
网上关于saveOrUpdate的说明如下:
saveOrUpdate(po)做下面的事: 
如果该po对象已经在本session中持久化了,在本session中执行saveOrUpdate不做任何事 
如果savaOrUpdate(新po)与另一个与本session关联的po对象拥有相同的持久化标识(identifier),抛出一个异常 
org.hibernate.NonUniqueObjectException: a different object with the same identifier value was already associated with the session: [org.itfuture.www.po.Xtyhb#5]
saveOrUpdate如果对象没有持久化标识(identifier)属性,对其调用save() ,否则update() 这个对象
===========

现在我有一个useinfo表,主键为ID,自增,其他还有name,age,sex属性,有一个useinfo类作为spring管理下的实体类对应这个表,所有useinfo表内字段在该类中都有属性对应和setter和getter方法

我用name,age作为筛选条件,执行hql,得到一个list<useinfo>
List<useinfo> lOI =this.getHibernateTemplate().find(
"from UserInfo ui where ui.name='" + userName + "' and ui.age ='" + age + "'");

得到该list后,我用list.get(0)取得第一个元素,并更新了age属性
lOI.get(0).setStep(1);

然后我试图把该对象更新回数据库
this.getHibernateTemplate().saveOrUpdate(lOI.get(0));
结果此时实际发生的动作是save(insert),而不是我期待的update

我的问题是,我在修改了age属性后,显然,数据库里已经没有了对应的该条记录,所以该对象从持久化状态变成了瞬态,但是它持有ID这个属性,id难道不是持久化标识吗?为什么此时系统会认为它没有持有持久化标识而是用了save动作




------解决方案--------------------
这么写当然不对了,lOI.get(0)取出的这个对象,不等同于直接从数库取出,所以你用saveOrUpdate()方法的话HibernateTemplate方法会当成一个插入的操作执行,而不是修改。如果你是直接从数据库中get出来这个实体,修改后再执行saveOrUpdate()方法,那么HibernateTemplate就会看成一个update而非insert。这是因为你由lOI.get(0)得到的对象是一个游离态。
就像你写的:
List<useinfo> lOI =this.getHibernateTemplate().find(
"from UserInfo ui where ui.name='" + userName + "' and ui.age ='" + age + "'");

this.getHibernateTemplate().saveOrUpdate(lOI.get(0));


上面两句是在不同的事务中进行的,它们的HibernateTemplate不是同一个实例,而在这里游离和持久态的标志是你的事务是不是关闭了,关闭后就变成游离态了,并不是你说的id难道是持久化标识。而你又在this.getHibernateTemplate一个类的实例去saveOrupdate这个对象,当然会当作了插入进行操作了。如果是在同一个HibernateTemplate实例下进行的就可以了,Spring既然有一个类就有它的用处,很明显你的写法不正确。。。