浏览 10941 次
精华帖 (0) :: 良好帖 (0) :: 新手帖 (0) :: 隐藏帖 (0)
|
|
---|---|
作者 | 正文 |
发表时间:2007-06-28
/**
*作者:张荣华(ahuaxuan) *2007-06-28 *转载请注明出处及作者 */ 解惑:在spring+hibernate中,只读事务是如何被优化的。
大家都知道,spring+hibernate的环境下,spring对只读事务会有特别的优化,那么spring是如何做到这个优化的呢?
Without ejb中写到,当事务被标识为只读事务时,某些可以针对只读事务进行优化的资源就可以执行相应的优化措施,比如说hibernate的session在只读事务模式下不会尝试检测和同步持久对象的状态的更新。另外还写到jdbc的connection可以通过调用setReadOnly(true)来切换到只读事务模式上来;但是大多数jdbc driver会忽略掉他。
我们知道spring中所谓的只读事务就是通过设置session的flushmode为never来实现的(http://www.iteye.com/topic/87426
)。那么把flushmode设置为never能给我们带来什么呢?
我们来看一下hibernate中JDBCTransaction中的方法:
java 代码
我们看一下那个managedFlush()方法,这个方法主要就是刷新一级缓存的一个方法:
java 代码
我们知道如果
session
的
flushmode
为
never
的时候,以上的方法是不会调用的,这样就可以省去很多
flush
的开销。于是命题就变成了
flush
操作有哪些开销了。
也许你要问
flush
和不
flush
有什么样的区别,在开销上有多大的区别呢。要看明白
hibernate
是怎么做
flush
的,那就必须要知道观察者模式了,实际上
session
是一个被观察者
(subject)
,而真正执行
flush
的是一个观察者
(observer),
我们来看一下下面这个图:
(
这个图是我画在纸上然后用手机拍下来的
)
从这里面我们可以看到
flush
实际上是由
DefaultFlushEventListener
来执行的,而且
sessionimpl
默认的只注册了一个
FlushEventListener
实例(为什么只有一个还要这样做,我估计他是为了扩展的需要,不知道
3.2
中是否就不止一个了呢?),这个
DefaultFlushEventListener
最终执行了
flush
的方法:
java 代码
由此我们看到
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
>
作者:张荣华,未经作者同意不得随意转载! 声明:ITeye文章版权属于作者,受法律保护。没有作者书面许可不得转载。
推荐链接
|
|
返回顶楼 | |
发表时间:2007-07-23
也就是说在使用spring+hibernate的时候,只读事务就是少一个flush对吧?
那使用spring+jdbc的时候,只读事务有哪些优化措施呢?是不是说就没有优化了呀,因为jdbc没有什么flush的说法呀。 |
|
返回顶楼 | |
发表时间:2007-07-24
annegu 写道 也就是说在使用spring+hibernate的时候,只读事务就是少一个flush对吧?
那使用spring+jdbc的时候,只读事务有哪些优化措施呢?是不是说就没有优化了呀,因为jdbc没有什么flush的说法呀。 直接使用jdbc好像没有什么优化不优化之说,我不知道把connection设置为readonly到底能带来多少性能的提高,估计没有,而且很多jdbc驱动会忽略这选项,所以直接使用jdbc应该是没有什么特别的优化的 |
|
返回顶楼 | |