Quantcast

Mybatis-spring "Cannot change the ExecutorType when there is an existing transaction"

classic Classic list List threaded Threaded
1 message Options
Reply | Threaded
Open this post in threaded view
|  
Report Content as Inappropriate
star

Mybatis-spring "Cannot change the ExecutorType when there is an existing transaction"

sanho
This post has NOT been accepted by the mailing list yet.
 nice to meet you !
>
> when two dao functions use  different ExecutorType and it is in a transaction,The above problems occur.
> I have learned that the root cause is " TransactionSynchronizationManager.bindResource(sessionFactory, holder);".
> It's key is sessionFactory,but not sessionFactory+ExecutorType.why can't we set the key as above? what's more,I don't find the Bad places with this way.
> sorry for my poor english,I hope you can realize.
> I want to know what's think over the way now!
>
> these are  my code:
>
> public class MybatisBindObject {
>        private SqlSessionFactory sqlSessionFactory;
>        private ExecutorType executorType;
>
>        private MybatisBindObject(SqlSessionFactory sqlSessionFactory,
>                        ExecutorType executorType) {
>                Assert.notNull(sqlSessionFactory, "No SqlSessionFactory specified");
>                Assert.notNull(executorType, "No ExecutorType specified");
>                this.sqlSessionFactory = sqlSessionFactory;
>                this.executorType = executorType;
>        }
>
>        @Override
>        public boolean equals(Object obj) {
>                if (!(obj instanceof MybatisBindObject))
>                        return false;
>                MybatisBindObject bindObject = (MybatisBindObject) obj;
>                return this.sqlSessionFactory.equals(bindObject.sqlSessionFactory)
>                                && this.executorType.equals(bindObject.executorType);
>        }
>
>        @Override
>        public int hashCode() {
>                return this.sqlSessionFactory.hashCode()*this.executorType.hashCode()+473;
>        }
>
>        public static MybatisBindObject getMybatisBindObject(SqlSessionFactory sqlSessionFactory,
>                        ExecutorType executorType){
>                return new MybatisBindObject(sqlSessionFactory,executorType);
>        }
> }
>
> --------------------------------
> --SqlSessionUtils--
>
>
>    public static SqlSession getSqlSession(
>            SqlSessionFactory sessionFactory,
>            ExecutorType executorType,
>            PersistenceExceptionTranslator exceptionTranslator) {
>
>        Assert.notNull(sessionFactory, "No SqlSessionFactory specified");
>        Assert.notNull(executorType, "No ExecutorType specified");
>        MybatisBindObject bindObject = MybatisBindObject.getMybatisBindObject(sessionFactory, executorType);
>        SqlSessionHolder holder = (SqlSessionHolder) TransactionSynchronizationManager.getResource(bindObject);
>
>        if (holder != null && holder.isSynchronizedWithTransaction()) {
>            if (holder.getExecutorType() != executorType) {
>                throw new TransientDataAccessResourceException(
>                        "Cannot change the ExecutorType when there is an existing transaction");
>            }
>
>            holder.requested();
>
>            if (logger.isDebugEnabled()) {
>                logger.debug("Fetched SqlSession [" + holder.getSqlSession() + "] from current transaction");
>            }
>
>            return holder.getSqlSession();
>        }
>
>        DataSource dataSource = sessionFactory.getConfiguration().getEnvironment().getDataSource();
>
>        // SqlSessionFactoryBean unwraps TransactionAwareDataSourceProxies but
>        // we keep this check for the case that SqlSessionUtils is called from custom code
>        boolean transactionAware = (dataSource instanceof TransactionAwareDataSourceProxy);
>        Connection conn;
>        try {
>            conn = transactionAware ? dataSource.getConnection() : DataSourceUtils.getConnection(dataSource);
>        } catch (SQLException e) {
>            throw new CannotGetJdbcConnectionException("Could not get JDBC Connection for SqlSession", e);
>        }
>
>        if (logger.isDebugEnabled()) {
>            logger.debug("Creating SqlSession with JDBC Connection [" + conn + "]");
>        }
>
>        // Assume either DataSourceTransactionManager or the underlying
>        // connection pool already dealt with enabling auto commit.
>        // This may not be a good assumption, but the overhead of checking
>        // connection.getAutoCommit() again may be expensive (?) in some drivers
>        // (see DataSourceTransactionManager.doBegin()). One option would be to
>        // only check for auto commit if this function is being called outside
>        // of DSTxMgr, but to do that we would need to be able to call
>        // ConnectionHolder.isTransactionActive(), which is protected and not
>        // visible to this class.
>        SqlSession session = sessionFactory.openSession(executorType, conn);
>
>        // Register session holder and bind it to enable synchronization.
>        //
>        // Note: The DataSource should be synchronized with the transaction
>        // either through DataSourceTxMgr or another tx synchronization.
>        // Further assume that if an exception is thrown, whatever started the transaction will
>        // handle closing / rolling back the Connection associated with the SqlSession.
>        if (TransactionSynchronizationManager.isSynchronizationActive()) {
>            if (!(sessionFactory.getConfiguration().getEnvironment().getTransactionFactory() instanceof SpringManagedTransactionFactory)
>                    && DataSourceUtils.isConnectionTransactional(conn, dataSource)) {
>                throw new TransientDataAccessResourceException(
>                        "SqlSessionFactory must be using a SpringManagedTransactionFactory in order to use Spring transaction synchronization");
>            }
>
>            if (logger.isDebugEnabled()) {
>                logger.debug("Registering transaction synchronization for SqlSession [" + session + "]");
>            }
>            holder = new SqlSessionHolder(session, executorType, exceptionTranslator);
>            TransactionSynchronizationManager.bindResource(bindObject, holder);
>            TransactionSynchronizationManager.registerSynchronization(new SqlSessionSynchronization(holder, sessionFactory,executorType));
>            holder.setSynchronizedWithTransaction(true);
>            holder.requested();
>        } else {
>            if (logger.isDebugEnabled()) {
>                logger.debug("SqlSession [" + session + "] was not registered for synchronization because synchronization is not active");
>            }
>        }
>
>        return session;
>    }
> ----------------------------
>
>
> wait for your reply!    thanks!
Loading...