hibernate及spring的一些细节问题

关于update方法有几个地方不明白。




类似上面的方法,调用 select 方法查询出一个实体类对象,方法外部对该对象进行修改,然后传入 update 方法修改。

由于 select 和 update 使用的是两个独立的session,所以调用 session.update 方法的时候会抛出异常,因为传入的obj状态属于托管状态,不是持久态,是这样没错吧。

public Object doSelectXXX(){
       Session session = HibernateUtil.getSession();
       Object result = session.get(....);
       session.close();
       return result;
}

public boolean doUpdateXXX(Object obj){
       Session session = HibernateUtil.getSession();
       session.beginTr....();
       session.update(obj);
       // commit
       session.close();
       return true;
}

/*类似上面的方法,调用 select 方法查询出一个实体类对象,方法外部对该对象进行修改,然后传入 update 方法修改。 

由于 select 和 update 使用的是两个独立的session,所以调用         session.update 方法的时候会抛出异常,因为传入的obj状态属于托管状态,不是持久态,是这样没错吧。*/

/*
下面是我的问题,在spring里集成了hibernate。使用hibernatetemplate类进行操作,配置了相应的事务,并且设置事务隔离级别为:REQUIRES_NEW,总是开启一个新的事务,我理解的spring对session事务的管理应该是方法执行之前打开事务,方法执行之后提交事务,同时关闭session,那么这就和以上的类似了。
按我预想的应该是会抛出异常的,但是却没有,不知道我哪里理解错了? 


以下是spring集成hibernate之后的简略代码。
*/

public Object doSelectXXX(){
       return getHibernateTemplate().get(......);
}

public boolean doUpdateXXX(Object obj){
       getHibernateTemplate().update(obj);
       return true;
}

 

 

1个回答

你的理解有点错误

Hibernate session中常用的保存操作只有:save, update, saveOrUpdate,delete;还有其他很多操作没有用过:persist(), merge(), lock(), refresh(), evict(), replicate() ,有必要弄清楚这些方法分别是做什么, 实体对象的状态会发生什么变化?

先看看这些方法中,从javadoc的注释可以得出:
临时 —> 持久
save,persist,saveOrUpdate

托管 —> 持久
update,saveOrUpdate,saveOrUpdateCopy , merge,lock,replicate,refresh

持久 —> 托管
evict

持久 —> 临时
delete

根据以上,可以看出托管->持久的方法是最多的。
那么以上各类情况下,各个方法有什么区别?应该怎样取舍?在hibernate3.2环境下,我得出以下结论:
1. save和perisit
几乎一样,都是持久化一个临时对象;
只是persist持久化的时间可能推迟到flunsh之前,而且perisit传入的对象为托管对象时,会报错,而save托管对象不会报错只是将id置null。

可以看出,在持久化一个临时对象时,只用save就行了。

  1. saveOrUpdate和merge saveOrUpdate将unsaved对象持久化或托管对象持久化; merge,从名字也能猜到是合并,跟saveOrUpdate相似,可以持久化托管和临时对象。 不同的是:在更新时候,merge将托管对象的属性复制到session中有相同标识符(但不相等)的持久对象(如果不存在,就从db load),也就是先select 后 update;倘若找不到相同标识符的对象,则置id为null,保存临时对象。返回的是持久对象,但是merge传入的对象还是托管的。

可以看出,只有在session中已经存在一个具有相同标识符的持久对象的时候,应该采用merge,此时用saveOrUpdate会报错。当然如果碰到这类情形,将对象属性copy到已经持久化的那个相同标识符对象上也是可以的,正因为如此我一般都没用过merge。再者merge在session中不存在相同标识对象时,会多一条select,往往我们并不需要。

  1. merge和replicate replicate,通过复制来持久化当前已经脱离session的托管对象,这点上看有点像merge,但是当传入一个临时对象则会报错,而且replicate后的传入的那个对象将是持久的,这也是跟merge不同。 通过参数ReplicationMode可以控制遇到相同记录时的行为。 如果是 ReplicationMode.EXCEPTION,则在复制时如果有重复的行数据,则抛出异常。ReplicationMode.IGNORE则忽略 异常。 ReplicationMode.OVERWRITE则会覆盖掉已有行数据。ReplicationMode.LATEST_VERSION则是在有重复时使用最新的版本进行控制。

可以看出,replicate在执行复制的时候,比起merge还是有更多可控行为,ReplicationMode.LATEST_VERSION还可以保证并发修改时只更新最新的版本。

  1. lock和refresh 相类似的,都将托管对象又重新持久化,而且可以指定查询时候的锁:
    • 当用户显式的使用数据库支持的SQL格式SELECT ... FOR UPDATE 发送SQL的时候,锁定级别设置为LockMode.UPGRADE
    • 当用户显式的使用Oracle数据库的SQL语句SELECT ... FOR UPDATE NOWAIT 的时候,锁定级别设置LockMode.UPGRADE_NOWAIT *当Hibernate在“可重复读”或者是“序列化”数据库隔离级别下读取数据的时候,锁定模式 自动设置为LockMode.READ。这种模式也可以通过用户显式指定进行设置。 *LockMode.NONE 代表无需锁定。在Transaction结束时, 所有的对象都切换到该模式上来。与session相关联的对象通过调用update() 或者saveOrUpdate()脱离该模式。 以上只有 LockMode.NONE,先从缓存查找持久对象;其他的都直接从数据库查找。

有些不同的是,lock还有检查对象版本的能力,如果指定的锁定模式是READ, UPGRADE 或 UPGRADE_NOWAIT,那么Session.lock()就 执行版本号检查。

refresh提供了比load更方便的查找能力,一个刚脱离了session的持久对象,如果用load还需要用id查找,那么refresh就可以直接传入托管对象刷新其状态了。

  1. delete和evict evict,从session的缓存中去除当前实例。执行后对象的改变将不再和数据库保持同步。当指定级联风格为'evict’时,会级联操作关联对象。在用于批量操作的时候,清空缓存,防止内存紧张。 delete,也会从session的缓存中去除当前实例,但flunsh时会执行数据库delete,之后对象就成了临时状态。 可以看出delete比起evict,不仅从session删除,还会从数据库删除。
Csdn user default icon
上传中...
上传图片
插入图片
抄袭、复制答案,以达到刷声望分或其他目的的行为,在CSDN问答是严格禁止的,一经发现立刻封号。是时候展现真正的技术了!
立即提问