有人真个测试过spring事务中readonly吗

有人真正测试过spring事务中readonly吗

最新测试结果 start...:

ahuaxuan 在回复中说的没错,在DataSourceUtils.prepareConnectionForTransaction(con, definition)中的确会设置readonly,我之前说的DataSourceTransactionManager中不设置readonly的说法是错误的。
但在oracle下,这个readonly确实有问题,我一步步测下来,原因就是出在 con.setAutoCommit(false) 这行代码上:
1. 如果 con.setReadOnly(true) 放在 con.setAutoCommit(false) 前面,就是代码现在的做法,readonly是不起作用的。
2. 反之,如果我把DataSourceUtils.prepareConnectionForTransaction(con, definition)  代码放在它的后面的时候,readonly 起了作用。


难道oracle的驱动对这个顺序还有影响吗,有点匪夷所思啊。
不知道在其他数据库中有没有影响。

//其中, DataSourceUtils.prepareConnectionForTransaction(con, definition)中会设置con.setReadOnly(true)
protected void doBegin(Object transaction, TransactionDefinition definition) {
....
....
Integer previousIsolationLevel = DataSourceUtils.prepareConnectionForTransaction(con, definition);
			txObject.setPreviousIsolationLevel(previousIsolationLevel);

			// Switch to manual commit if necessary. This is very expensive in some JDBC drivers,
			// so we don't want to do it unnecessarily (for example if we've explicitly
			// configured the connection pool to set it already).
			
			if (con.getAutoCommit()) {
				
				txObject.setMustRestoreAutoCommit(true);
				
				if (logger.isDebugEnabled()) {
					logger.debug("Switching JDBC Connection [" + con + "] to manual commit");
				}
				con.setAutoCommit(false);
			}
...
...
}


最新测试结果 end...


为何readonly不起作用,有人真正测过吗?

环境
1. spring2.5 + ibatis/jdbctemplate(测了这两个) + oracle10,
2. 驱动ojdbc14.jar
3. 连接池 dbcp和c3p0都测了。

先看部分后台,证明调用的方法确实开启了readonly:
21/01/2009 16:43:01,457 <DEBUG> (org.springframework.transaction.interceptor.NameMatchTransactionAttributeSource)- Adding transactional method [search*] with attribute [PROPAGATION_REQUIRED,ISOLATION_DEFAULT,readOnly]


21/01/2009 17:10:00,864 <DEBUG> (org.springframework.jdbc.datasource.DataSourceTransactionManager)- Creating new transaction with name [com.me.service.logic.ViewService.searchLeave]: PROPAGATION_REQUIRED,ISOLATION_DEFAULT,readOnly


先在oracle里面测试下
set transaction read only;
update stu set title = 'oh,god' where id='12345'

抛错,证明oracle对read only有效:
ORA-01456: may not perform insert/delete/update operation inside a READ ONLY transaction


程序中的配置
	<aop:config>
		<aop:pointcut id="serviceOperation"
			expression="execution(* com.me.service.logic.*ServiceImpl.*(..))" />
		<aop:advisor pointcut-ref="serviceOperation" advice-ref="txAdvice" />
	</aop:config>

	<tx:advice id="txAdvice" transaction-manager="transactionManager">
		<tx:attributes>
			<tx:method name="search*" read-only="true" />
		</tx:attributes>
	</tx:advice>


//ViewServiceImpl:
public List searchLeave(Leave leave) {
	
        //update stu set title = 'oh,god' where id='12345'
        int j = viewDAO.updateStu();
		
	return viewDAO.searchLeave(leave);
}


以上的searchLeave方法应该抛出错误的。readonly不允许update。
但一切似乎都没有效果。







1 楼 myyate 2009-01-21  
没有测试过,不过你可以换种配置方式:@Transactional(readonly="true")试试看,可能你这种用schema配置哪儿自己弄错了;
不过楼主不要首先怀疑spring,人家发布都几年了,如果连只读事物都没有搞定,你觉得可能吗?
2 楼 geng2483759 2009-01-21  
@Transactional(readonly="true") 也测试过,也是不行。

并不是只是怀疑spring,我只是想弄清楚其中的缘由,不然怎么能在项目中使用呢。是吧。

我相信大家很多都在项目中配了readonly,可以动手测一下。
3 楼 workman93 2009-01-22  
geng2483759 写道

@Transactional(readonly="true") 也测试过,也是不行。 并不是只是怀疑spring,我只是想弄清楚其中的缘由,不然怎么能在项目中使用呢。是吧。 我相信大家很多都在项目中配了readonly,可以动手测一下。

我也正在困扰中,我使用SQL 2005貌似也没有起作用。楼主要是有结果的话麻烦告知一下,非常感谢。有人真个测试过spring事务中readonly吗
4 楼 theone 2009-01-31  
你应该仔细看一下Spring的文档,在事务那一章有明确的解释:

“只读事务”并不是一个强制选项,它只是一个“暗示”,提示数据库驱动程序和数据库系统,这个事务并不包含更改数据的操作,那么JDBC驱动程序和数据库就有可能根据这种情况对该事务进行一些特定的优化,比方说不安排相应的数据库锁,以减轻事务对数据库的压力,毕竟事务也是要消耗数据库的资源的。

但是你非要在“只读事务”里面修改数据,也并非不可以,只不过对于数据一致性的保护不像“读写事务”那样保险而已。

因此,“只读事务”仅仅是一个性能优化的推荐配置而已,并非强制你要这样做不可。
5 楼 xiao007hua 2009-02-01  
看了楼上的论述,实在是令人难受,不得已回一篇帖子


DefaultTransactionDefinition trans = new DefaultTransactionDefinition();

trans.setReadOnly(true);
trans.setPropagationBehavior(DefaultTransactionDefinition.PROPAGATION_NEVER);

以上的事务配置是绝对支持只读的,

import org.springframework.transaction.support.DefaultTransactionDefinition;
6 楼 theone 2009-02-01  
拜托你好好学习一下Spring的事务好不好?PROPAGATION_NEVER你知道是什么意思嘛? 不知道的话,别在这里瞎误导,搞笑嘛。PROPAGATION_NEVER和readOnly压根两码事。PROPAGATION_NEVER是禁止事务传播,懂不懂?
7 楼 geng2483759 2009-02-04  
theone 写道
你应该仔细看一下Spring的文档,在事务那一章有明确的解释:

“只读事务”并不是一个强制选项,它只是一个“暗示”,提示数据库驱动程序和数据库系统,这个事务并不包含更改数据的操作,那么JDBC驱动程序和数据库就有可能根据这种情况对该事务进行一些特定的优化,比方说不安排相应的数据库锁,以减轻事务对数据库的压力,毕竟事务也是要消耗数据库的资源的。

但是你非要在“只读事务”里面修改数据,也并非不可以,只不过对于数据一致性的保护不像“读写事务”那样保险而已。

因此,“只读事务”仅仅是一个性能优化的推荐配置而已,并非强制你要这样做不可。


1. 和spring文档没有任何关系,spring事务仅仅是一层封装,最后都要调用底层驱动的setReadonly方法来开启。
2.在大多数数据库系统下,只读事务里面是不可以修改数据,并且,在同一个事务里面同一个sql读出来的同一条记录是不会变化的,这是我们开启readonly最重要的原因:我们需要能够可重复读。
3. 在一个系统中,为了保证在同一个事务中读取数据的一致性,对一系列读操作开启readonly是很重要的做法,并不仅仅是性能优化的推荐配置。
4. 最重要的是,spring的DataSourceTransactionManager确实不支持readonly,我开头的连接中已经给出了原因。
8 楼 daquan198163 2009-02-04  
readonly不是用来保证“读取数据的一致性”的,隔离级别是由它前面的相邻那个属性配置的
例如:PROPAGATION_REQUIRED,REPEATABLE READ,readOnly,-MyCheckedException,3

readOnly表示对应的事务应该被最优化为只读事务,例如在使用Hibernate时避免dirty checking
9 楼 grave 2009-02-04  
难道现在Connection和Transaction都被混为一谈了?
10 楼 pantiansheng 2009-07-23  
By setting the JDBC connection to read-only, Spring prevents a distracted user from persisting changes by flushing the Hibernate session to the database.

11 楼 ahuaxuan 2009-07-23  
1.readonly语义不是所有的数据库驱动都支持的。
2.在spring+hibernate的条件下,readonly有一些优化
http://www.iteye.com/topic/95124
12 楼 geng2483759 2009-07-24  
ahuaxuan 写道
1.readonly语义不是所有的数据库驱动都支持的。
2.在spring+hibernate的条件下,readonly有一些优化
http://www.iteye.com/topic/95124

说的没错, 有的数据库驱动是不支持readonly的。但在oracle下绝对支持,上面也已经验证过了。
顺便回答下你帖子里一个问题: 使用jdbc不但没有优化,压根jdbc的这个DataSourceTransactionManager就不支持readonly。因为它源代码里面没有一处调用con.setReadOnly(true)之类的方法。
而HibernateTransactionManager中正如你所说的会有这么一段:
if (definition.isReadOnly() && txObject.isNewSession()) {
                                // Just set to NEVER in case of a new Session for this transaction.
                                session.setFlushMode(FlushMode.NEVER);
                        }


详细分析: http://www.iteye.com/problems/10624
13 楼 ahuaxuan 2009-07-26  
geng2483759 写道
ahuaxuan 写道
1.readonly语义不是所有的数据库驱动都支持的。
2.在spring+hibernate的条件下,readonly有一些优化
http://www.iteye.com/topic/95124

说的没错, 有的数据库驱动是不支持readonly的。但在oracle下绝对支持,上面也已经验证过了。
顺便回答下你帖子里一个问题: 使用jdbc不但没有优化,压根jdbc的这个DataSourceTransactionManager就不支持readonly。因为它源代码里面没有一处调用con.setReadOnly(true)之类的方法。
而HibernateTransactionManager中正如你所说的会有这么一段:
if (definition.isReadOnly() && txObject.isNewSession()) {
                                // Just set to NEVER in case of a new Session for this transaction.
                                session.setFlushMode(FlushMode.NEVER);
                        }


详细分析: http://www.iteye.com/problems/10624

这位同学,你最好修改一下你的结论,DataSourceTransactionManager不是不设置readonly,只是你没有看到,DataSourceTransactionManager#doBegin()方法中有这么一句:Integer previousIsolationLevel = DataSourceUtils.prepareConnectionForTransaction(con, definition);,你跟进去看看会发现:


public static Integer prepareConnectionForTransaction(Connection con, TransactionDefinition definition)
			throws SQLException {

		Assert.notNull(con, "No Connection specified");

		// Set read-only flag.
		if (definition != null && definition.isReadOnly()) {
			try {
				if (logger.isDebugEnabled()) {
					logger.debug("Setting JDBC Connection [" + con + "] read-only");
				}
				con.setReadOnly(true);
			}
			catch (Throwable ex) {
				// SQLException or UnsupportedOperationException
				// -> ignore, it's just a hint anyway.
				logger.debug("Could not set JDBC Connection read-only", ex);
			}
		}

		。。。。。。。。。。。。。。。。。
	}


所以即使是spring+jdbc还是会设置readonly的
14 楼 jayxu 2009-07-27  
ahuaxuan 写道
1.readonly语义不是所有的数据库驱动都支持的。
2.在spring+hibernate的条件下,readonly有一些优化
http://www.iteye.com/topic/95124

是的

有些数据库驱动不支持readonly的

像我就从来都没能用上readonly
15 楼 summeryhrb 2009-07-27  
是通过数据库的事务控制实现的,spring只是把事务控制的参数传给jdbc而已。
关于测试的问题,完全可以通过多线程模拟出来,模拟测试+源码研究
16 楼 KimShen 2009-07-27  
READ ONLY是需要底层数据库支持的! 至少MySQL中没有问题
17 楼 geng2483759 2009-08-06  
ahuaxuan 说的没错,的确是设置了,但readonly还是不起作用,最新测试结果看我正文中的修改。
18 楼 gates_lee 2009-08-08  
<ol>
<li>readonly并不是所有数据库都支持的,不同的数据库下会有不同的结果。</li>
<li>设置了readonly后,connection都会被赋予readonly,效果取决于数据库的实现。</li>
<li>在ORM中,设置了readonly会赋予一些额外的优化,例如在Hibernate中,会被禁止flush等。</li>
</ol>
19 楼 geng2483759 2009-08-08  
<div class="quote_title">gates_lee 写道</div>
<div class="quote_div"><ol>
<li>readonly并不是所有数据库都支持的,不同的数据库下会有不同的结果。</li>
<li>设置了readonly后,connection都会被赋予readonly,效果取决于数据库的实现。</li>
<li>在ORM中,设置了readonly会赋予一些额外的优化,例如在Hibernate中,会被禁止flush等。</li>
</ol></div>
<p>oracle在odbc14的jar下是绝对支持readonly的,这点吾容置疑。但为何会出现我文中所说的现象,这才是本质问题。</p>
20 楼 panny1982 2009-10-19  
你如果纯用了jdbc那是肯定有效果的,但如果用了Ibatis,Hibernate的第三方,那么往往readonly会被忽略,其实如果你是纯粹取数据,不声明事务也没关系。