??xml version="1.0" encoding="utf-8" standalone="yes"?> 游离状态的实例可以通过调用save()、persist()或者saveOrUpdate()Ҏ(gu)q行持久化?br />持久化实例可以通过调用 delete()变成q状态。通过get()或load()Ҏ(gu)得到的实例都是持久化状态的?br />q状态的实例可以通过调用 update()?saveOrUpdate()、lock()或者replicate()q行持久化?/p>
save()和persist()会(x)引发SQL的INSERTQdelete()?x)引发SQLDELETEQ?br />而update()或merge()?x)引发SQLUPDATE。对持久化(persistentQ实例的修改在刷新提交的时候会(x)被检到Q?br />它也?x)引起SQLUPDATE。saveOrUpdate()或者replicate()?x)引发SQLINSERT或者UPDATE 二、save 和update区别 ?update 和saveOrUpdate区别 saveOrUpdate()做下面的? ?persist和save区别 persist() is well defined. It makes a transient instance persistent. However, persist() also guarantees that it will not execute an INSERT statement if it is save() does not guarantee the same, it returns an identifier, and if an INSERT --------------------------------------------------------------------------------- 2Qpersist"保证"Q当它在一个transaction外部被调用的时候ƈ不触发一个Sql InsertQ这个功能是很有用的Q?br />当我们通过l承Session/persistence context来封装一个长?x)话程的时候,一个persistq样的函数是需要的?/p>
3Qsave"不保?W??它要q回标识W,所以它?x)立x行Sql insertQ不是不是在transaction内部q是外部 ?flush和update区别 ?lock和update区别 参考内容:(x)
JDBC事务由Connnection理Q也是_(d)事务理实际上是在JDBC Connection
中实现。事务周期限于Connection的生命周期之?br>
JTA 事务理则由 JTA 容器实现QJTA 容器对当前加入事务的众多Connection q?br>行调度,实现其事务性要求。JTA的事务周期可横跨多个JDBC Connection生命周期?br>
二、在了解jdbc和jta事务的基上,再来讨论hibernate的两U事?br>对于ZJDBC Transaction的Hibernate 事务理机制而言Q事务管理在Session 所依托的JDBC Connection
中实玎ͼ事务周期限于Session的生命周期?br>
对于ZJTA事务的Hibernate而言QJTA事务横跨可横跨多个Session?br>三、hibernate中写法的不同
jdbc的写?br>
public void saveUser()
{
Session session = sessionFactory.openSession();
Transaction tx = session.beginTransaction();
session.save(user);
tx.commit();
session.close();
}
必须在session.close()之前commit或者rollback
jta写法
public void saveUser()
{
Session session = sessionFactory.openSession();
Transaction tx = session.beginTransaction();
session.save(user);
session.close();
Session session1 = sessionFactory.openSession();
session1.save(user1);
session.close();
tx.commit();
}
commit和rollback可以在session.close()之后执行.
同时应该注意的一Ҏ(gu)Q事务是不能嵌套的,在用jta的事务的情况下,如果要让一个事务跨两?br>
session,则必d两个session的外层开始事务和完成事务。而不能再在session内部开始事务和完成事务?/span>
2Q在配合spring使用的时候会(x)可能?x)抛出org.springframework.dao.InvalidDataAccessApiUsageException
先说1Q这个异常的抛出原因和解军_法见q里Q?br>javaeye上有了很好的事例:http://www.javaeye.com/topic/11581
解决办法可以用mergeQ也可以别的办法?br>出现的原因,可以参考一下我前边的文章中merge和update的区别的内容?br>http://www.aygfsteel.com/dreamstone/archive/2007/07/29/133071.html
2的解军_法:(x)在这?br>springside的一文章做了详l说?br>http://calvin.blog.javascud.org/post/46.htm
好了Q现在问题解决了Q但关于open-session-in-view的用还有一些探讨,是否应该使用Q用的好处与坏处?br>见这两篇jdon上的文章:
http://www.jdon.com/jivejdon/thread/22374.html
http://www.jdon.com/jivejdon/thread/28955.html
在所有之前,说明一下,对于hibernateQ它的对象有三种状态,transient、persistent、detached
下边是常见的译办法Q?br />transientQ瞬态或者自由?br />persistentQ持久化状?br />detachedQ脱状态或者游L?/p>
把这一Ҏ(gu)在第一位的原因是因一Ҏ(gu)最常用的?br />save的作用是把一个新的对象保?br />update是把一个脱状态的对象保存
q个是比较好理解的,思义QsaveOrUpdate基本上就是合成了save和update
引用hibernate reference中的一D话来解释他们的使用场合和区?br />通常下面的场景会(x)使用update()或saveOrUpdate()Q?
E序在第一个session中加载对?
该对象被传递到表现?
对象发生了一些改?
该对象被q回C务逻辑?
E序调用W二个session的update()Ҏ(gu)持久q些改动
如果对象已经在本session中持久化了,不做M?
如果另一个与本session兌的对象拥有相同的持久化标?identifier)Q抛Z个异?
如果对象没有持久化标?identifier)属性,对其调用save()
如果对象的持久标?identifier)表明其是一个新实例化的对象Q对其调用save()
如果对象是附带版本信息的Q通过<version>?lt;timestamp>Q?q且版本属性的D明其是一个新实例化的对象Qsave()它?
否则update() q个对象
q个是最qL(fng)的一对,表面上看h使用哪个都行Q在hibernate reference文档中也没有明确的区分他?
q里l出一个明的区分。(可以跟进src看一下,虽然实现步骤cMQ但是还是有l微的差别)
q里参?a >http://opensource.atlassian.com/projects/hibernate/browse/HHH-1682中的一个说明:(x)
---------------------------------------------------------------------------------
I found that a lot of people have the same doubt. To help to solve this issue
I'm quoting Christian Bauer:
"In case anybody finds this thread...
it doesn't guarantee that the identifier value will be assigned to the persistent
instance immediately, the assignment might happen at flush time. The spec doesn't say
that, which is the problem I have with persist().
called outside of transaction boundaries. This is useful in long-running conversations
with an extended Session/persistence context.A method like persist() is required.
has to be executed to get the identifier (e.g. "identity" generator, not "sequence"),
this INSERT happens immediately, no matter if you are inside or outside of a transaction. This is not good in a long-running conversation with an extended Session/persistence context."
单翻译一下上边的句子的主要内容:(x)
1Qpersist把一个瞬态的实例持久化,但是q?不保?标识W被立刻填入到持久化实例中,标识W的填入可能被推q?br />到flush的时间?/p>
?saveOrUpdateCopy,merge和update区别
首先说明merge是用来代替saveOrUpdateCopy的,q个详细见这?br />http://www.aygfsteel.com/dreamstone/archive/2007/07/28/133053.html
然后比较update和merge
update的作用上边说了,q里说一下merge?br />如果session中存在相同持久化标识(identifier)的实例,用用L(fng)出的对象的状态覆盖旧有的持久实例
如果session没有相应的持久实例,则尝试从数据库中加蝲Q或创徏新的持久化实?最后返回该持久实例
用户l出的这个对象没有被兌到session上,它依旧是q?
重点是最后一句:(x)
当我们用update的时候,执行完成后,我们提供的对象A的状态变成持久化状?br />但当我们使用merge的时候,执行完成Q我们提供的对象Aq是q状态,hibernate或者new了一个BQ或者检索到
一个持久对象BQƈ把我们提供的对象A的所有的值拷贝到q个BQ执行完成后B是持久状态,而我们提供的Aq是托管状?/p>
q两个的区别好理?br />update操作的是在脱状态的对象
而flush是操作的在持久状态的对象?br />默认情况下,一个持久状态的对象是不需要update的,只要你更改了对象的|{待hibernate flushp?br />保存到数据库了。hibernate flush发生再几U情况下Q?br />1Q调用某些查询的时?br />2Qtransaction commit的时?br />3Q手动调用flush的时?
update是把一个已l更改过的脱状态的对象变成持久状?br />lock是把一个没有更改过的脱状态的对象变成持久状?br />对应更改一个记录的内容Q两个的操作不同Q?br />update的操作步骤是Q?br />Q?Q更改脱的对象->调用update
lock的操作步骤是Q?br />(2)调用lock把对象从q状态变成持久状?->更改持久状态的对象的内?->{待f(xi)lush或者手动flush
http://www.aygfsteel.com/iamtin/archive/2006/03/06/33910.aspx
http://opensource.atlassian.com/projects/hibernate/browse/HHH-1682
http://www.redsaga.com/hibernate-ref/3.x/zh-cn/html/objectstate.html
hibernate的查询有很多,Query,find,Criteria,get,load
query使用hsql语句Q可以设|参数是常用的一U方?/p>
criteria的方式,量避免了写hql语句Q看h更面向对象了?/p>
find方式Q这U方式已l被新的hibernate丢弃见这?br>http://www.aygfsteel.com/dreamstone/archive/2007/07/28/133053.html
get?span id=highlight_tag style="PADDING-RIGHT: 0px; PADDING-LEFT: 0px; FONT-WEIGHT: bold; PADDING-BOTTOM: 0px; COLOR: blue; PADDING-TOP: 0px; BACKGROUND-COLOR: #ccffff; blue: ">load方式是根据id取得一个记?br>下边详细说一下get?span id=highlight_tag style="PADDING-RIGHT: 0px; PADDING-LEFT: 0px; FONT-WEIGHT: bold; PADDING-BOTTOM: 0px; COLOR: blue; PADDING-TOP: 0px; BACKGROUND-COLOR: #ccffff; blue: ">load的不同,因ؓ(f)有些时候ؓ(f)了对比也?x)?span id=highlight_tag style="PADDING-RIGHT: 0px; PADDING-LEFT: 0px; FONT-WEIGHT: bold; PADDING-BOTTOM: 0px; COLOR: red; PADDING-TOP: 0px; BACKGROUND-COLOR: #ffeeee; red: ">find加进来?/p>
1Q从q回l果上对比:(x)
load方式索不到的话会(x)抛出org.hibernate.ObjectNotFoundException异常
getҎ(gu)索不到的话会(x)q回null
2Q从索执行机制上Ҏ(gu)Q?br>getҎ(gu)?span id=highlight_tag style="PADDING-RIGHT: 0px; PADDING-LEFT: 0px; FONT-WEIGHT: bold; PADDING-BOTTOM: 0px; COLOR: red; PADDING-TOP: 0px; BACKGROUND-COLOR: #ffeeee; red: ">findҎ(gu)都是直接从数据库中检?br>?span id=highlight_tag style="PADDING-RIGHT: 0px; PADDING-LEFT: 0px; FONT-WEIGHT: bold; PADDING-BOTTOM: 0px; COLOR: blue; PADDING-TOP: 0px; BACKGROUND-COLOR: #ccffff; blue: ">loadҎ(gu)的执行则比较复杂
1,首先查找session的persistent Context中是否有~存Q如果有则直接返?br>2,如果没有则判断是否是lazyQ如果不是直接访问数据库索,查到记录q回Q查不到抛出异常
3,如果是lazy则需要徏立代理对象,对象的initialized属性ؓ(f)falseQtarget属性ؓ(f)null
4, 在访问获得的代理对象的属性时,索数据库Q如果找到记录则把该记录的对象复制到代理对象的target
上,q将initialized=trueQ如果找不到抛出异??br>
以前的策略是Q?br>量l出全的接口Q这样减用L(fng)代码量,所以filter直接q回collectionQiterate直接q回
iterate。但q样的结果是q度的提供接口,造成了学?fn)上的负担和选择上的负担。如何记住这些函敎ͼ如何在众多函?br>中选择是个ȝ事情?br>凡是做java的都知道Q用一个java的东西最辛苦的是选择Q在开源的世界里边选择一个适合自己的工E,再在q个选择的工E里辚w择实现Ҏ(gu)
因ؓ(f)可能提供很多U实现方法,而且有些q是deprecated的?/p>
现在的策略:(x)
量化接口,或减函敎ͼ或者简化函数名Q例如把saveOrUpdateCopy变成merge?br>q样的好处是记忆学习(fn)负担。多写几句代码不是特别麻烦。其实我个h来讲更喜Ƣ现在的感觉?br>以前的策略其实很大程度上是满程序员的个人需求,更有成就感。但不适合使用者的需求?/p>
okQ无论如何现在的情况是更好了?/p>