问题描述:
http://www.iteye.com/topic/319768
经过测试加上源代码,发现, 如果你使用的是DataSourceTransactionManager来管理事务,readonly是不起作用的:(HibernateTransactionManager是起作用的,后面有源码分析)
先看源码:
1. DataSourceTransactionManager.doBegain 方法:
2. HibernateTransactionManager.doBegain方法中的一段:
可以看出, DataSourceTransactionManager.doBegain方法中没有一处来判断readonly的,所以不起作用,如果我加上:
那么可以成功,看后台:
结论:如果你使用DataSourceTransactionManager来控制事务,即使你开启了readonly也是无效的。当然你可以自己修改源代码,加上readonly的判断
但为何spring不控制在DataSourceTransactionManager的readonly,而开启在HibernateTransactionManager的呢,这是个问题!
http://www.iteye.com/topic/319768
经过测试加上源代码,发现, 如果你使用的是DataSourceTransactionManager来管理事务,readonly是不起作用的:(HibernateTransactionManager是起作用的,后面有源码分析)
- <bean id="transactionManager"
- class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
- <property name="dataSource" ref="dataSource" />
- </bean>
- <tx:advice id="txAdvice" transaction-manager="transactionManager">
- <tx:attributes>
- <tx:method name="search*" read-only="true" />
- </tx:attributes>
- </tx:advice>
先看源码:
1. DataSourceTransactionManager.doBegain 方法:
- protected void doBegin(Object transaction, TransactionDefinition definition) {
- DataSourceTransactionObject txObject = (DataSourceTransactionObject) transaction;
- Connection con = null;
- try {
- if (txObject.getConnectionHolder() == null ||
- txObject.getConnectionHolder().isSynchronizedWithTransaction()) {
- Connection newCon = this.dataSource.getConnection();
- if (logger.isDebugEnabled()) {
- logger.debug("Acquired Connection [" + newCon + "] for JDBC transaction");
- }
- txObject.setConnectionHolder(new ConnectionHolder(newCon), true);
- }
- txObject.getConnectionHolder().setSynchronizedWithTransaction(true);
- con = txObject.getConnectionHolder().getConnection();
- 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);
- }
- txObject.getConnectionHolder().setTransactionActive(true);
- int timeout = determineTimeout(definition);
- if (timeout != TransactionDefinition.TIMEOUT_DEFAULT) {
- txObject.getConnectionHolder().setTimeoutInSeconds(timeout);
- }
- // Bind the session holder to the thread.
- if (txObject.isNewConnectionHolder()) {
- TransactionSynchronizationManager.bindResource(getDataSource(), txObject.getConnectionHolder());
- }
- }
- catch (SQLException ex) {
- DataSourceUtils.releaseConnection(con, this.dataSource);
- throw new CannotCreateTransactionException("Could not open JDBC Connection for transaction", ex);
- }
- }
2. HibernateTransactionManager.doBegain方法中的一段:
- protected void doBegin(Object transaction, TransactionDefinition definition)
- {
- //省略一些代码
- if(!definition.isReadOnly() && !txObject.isNewSession())
- {
- FlushMode flushMode = session.getFlushMode();
- if(flushMode.lessThan(FlushMode.COMMIT))
- {
- session.setFlushMode(FlushMode.AUTO);
- txObject.getSessionHolder().setPreviousFlushMode(flushMode);
- }
- }
- }
可以看出, DataSourceTransactionManager.doBegain方法中没有一处来判断readonly的,所以不起作用,如果我加上:
- protected void doBegin(Object transaction, TransactionDefinition definition) {
- //硬代码:con.setReadOnly(true)
- con.setReadOnly(true);
- int timeout = determineTimeout(definition);
- if (timeout != TransactionDefinition.TIMEOUT_DEFAULT) {
- txObject.getConnectionHolder().setTimeoutInSeconds(timeout);
- }
- }
那么可以成功,看后台:
- nested exception is java.sql.SQLException: ORA-01456: may not perform insert/delete/update operation inside a READ ONLY transaction
- at org.springframework.jdbc.support.SQLStateSQLExceptionTranslator.translate(SQLStateSQLExceptionTranslator.java:124)
结论:如果你使用DataSourceTransactionManager来控制事务,即使你开启了readonly也是无效的。当然你可以自己修改源代码,加上readonly的判断
但为何spring不控制在DataSourceTransactionManager的readonly,而开启在HibernateTransactionManager的呢,这是个问题!