/**
*作者:张荣华(ahuaxuan)
*2007-06-28
*转载请注明出处及作者
*/
解惑:在spring+hibernate中,只读事务是如何被优化的。
大家都知道,spring+hibernate的环境下,spring对只读事务会有特别的优化,那么spring是如何做到这个优化的呢?
Without ejb中写到,当事务被标识为只读事务时,某些可以针对只读事务进行优化的资源就可以执行相应的优化措施,比如说hibernate的session在只读事务模式下不会尝试检测和同步持久对象的状态的更新。另外还写到jdbc的connection可以通过调用setReadOnly(true)来切换到只读事务模式上来;但是大多数jdbc driver会忽略掉他。
我们来看一下hibernate中JDBCTransaction中的方法:
java 代码
- publicvoid commit()
throws
HibernateException {
-
if
(!begun) {
- thrownew TransactionException(
"Transaction not successfully started"
);
- }
-
- log.debug(
"commit"
);
-
-
if
( !transactionContext.isFlushModeNever() && callback ) {
- transactionContext.managedFlush();
- }
-
-
- beforeTransactionCompletion();
-
if
( callback ) {
- jdbcContext.beforeTransactionCompletion(
this
);
- }
-
-
try
{
- commitAndResetAutoCommit();
-
- log.debug(
"committed JDBC Connection"
);
- committed =
true
;
-
if
( callback ) {
- jdbcContext.afterTransactionCompletion(
true
,
this
);
- }
- afterTransactionCompletion( Status.STATUS_COMMITTED );
- }
-
catch
(SQLException e) {
- log.error(
"JDBC commit failed"
, e);
- commitFailed =
true
;
-
if
( callback ) {
- jdbcContext.afterTransactionCompletion(
false
,
this
);
- }
- afterTransactionCompletion( Status.STATUS_UNKNOWN );
- thrownew TransactionException(
"JDBC commit failed"
, e);
- }
-
finally
{
- closeIfRequired();
- }
- }
我们看一下那个managedFlush()方法,这个方法主要就是刷新一级缓存的一个方法:
java 代码
- public
void
managedFlush() {
-
if
( isClosed() ) {
- log.trace(
"skipping auto-flush due to session closed"
);
-
return
;
- }
- log.trace(
"automatically flushing session"
);
- flush();
-
-
if
( childSessionsByEntityMode !=
null
) {
- Iterator iter = childSessionsByEntityMode.values().iterator();
-
while
( iter.hasNext() ) {
- ( (Session) iter.next() ).flush();
- }
- }
- }
我们知道如果
session
的
flushmode
为
never
的时候,以上的方法是不会调用的,这样就可以省去很多
flush
的开销。于是命题就变成了
flush
操作有哪些开销了。
也许你要问
flush
和不
flush
有什么样的区别,在开销上有多大的区别呢。要看明白
hibernate
是怎么做
flush
的,那就必须要知道观察者模式了,实际上
session
是一个被观察者
(subject)
,而真正执行
flush
的是一个观察者
(observer),
我们来看一下下面这个图:
(
这个图是我画在纸上然后用手机拍下来的
)
从这里面我们可以看到
flush
实际上是由
DefaultFlushEventListener
来执行的,而且
sessionimpl
默认的只注册了一个
FlushEventListener
实例(为什么只有一个还要这样做,我估计他是为了扩展的需要,不知道
3.2
中是否就不止一个了呢?),这个
DefaultFlushEventListener
最终执行了
flush
的方法:
java 代码
- public
void
onFlush(FlushEvent event)
throws
HibernateException {
-
final
EventSource source = event.getSession();
-
if
( source.getPersistenceContext().hasNonReadOnlyEntities() ) {
-
- flushEverythingToExecutions(event);
-
-
- performExecutions(source);
-
- postFlush(source);
-
-
if
( source.getFactory().getStatistics().isStatisticsEnabled() ) {
- source.getFactory().getStatisticsImplementor().flush();
- }
-
- }
- }
由此我们看到
hibernate
在执行
flush
操作的时候还是做了不少事情的,它不但要把持久对象刷到数据库,而且还要把其管理的对象也都刷到数据库中,这是一个很大的操作。同时如果你使用了二级缓存,
flush
操作也会涉及到它,而且在
flush
时还要判断哪些时插入的,哪些是更新的,哪些是删除的等等,
flush
完了还得更新一级缓存等。
其实我只是对
flush
作了最简单的概括和描述,事实上从代码上看来它远比我们想象的要来得复杂的多。
在对
flush
简单得了解了之后,我们再来讨论一下:为什么要把查询设置为只读事务。因为一个本来只是查询的操作,却要在事务提交时多做这么多事情,这显然是不合理的,所以
hibernate
才给
session
的设置了这么一个
flushmode
,那么只要这个
mode
为
never
,就可以免去这些不必要的操作。而
spring
在对
hibernate
的支持时也充分的考虑到了这一点,所以就把只读事务的
session
的
flush mode
设置为了
never
。这样我们事务提交时就不会执行
flush
操作了。
总结:
所以说,我们在使用
spring
时一定要注意把查询的操作定义成只读事务,这个可以给我们带来不必要的开销,比如看如下配置。
<
property
name
=
"transactionAttributes"
>
<
props
>
<
prop
key
=
"do*"
>
PROPAGATION_REQUIRED
prop
>
<
prop
key
=
"get*"
>
PROPAGATION_REQUIRED,readOnly
prop
>
<
prop
key
=
"load*"
>
PROPAGATION_REQUIRED,readOnly
prop
>
<
prop
key
=
"find*"
>
PROPAGATION_REQUIRED,readOnly
prop
>
<
prop
key
=
"list*"
>
PROPAGATION_REQUIRED,readOnly
prop
>
props
>
property
>
或者事务的传播途径最好能设置为
supports
(运行在当前的事务范围内,如果当前没有启动事务,那么就不在事务范围内运行)或者
not supports
(不在事务范围内执行,如果当前启动了事务,那么挂起当前事务),也就是说查询操作其实可以不必要真正的开启一个数据库事务,因为开启一个真正的数据库事务又会给我们带来一点点可以忽略不计的开销。下面是一个例子
<
property
name
=
"transactionAttributes"
>
<
props
>
<
prop
key
=
"do*"
>
PROPAGATION_REQUIRED
prop
>
<
prop
key
=
"get*"
>
PROPAGATION_SUPPORTS,readOnly
prop
>
<
prop
key
=
"load*"
>
PROPAGATION_SUPPORTS,readOnly
prop
>
<
prop
key
=
"find*"
>
PROPAGATION_SUPPORTS,readOnly
prop
>
<
prop
key
=
"list*"
>
PROPAGATION_SUPPORTS,readOnly
prop
>
props
>
property
>
评论排行榜