mybatis--MapperProxy事務


上篇 詳細分析了org.mybatis.spring.mapper.MapperScannerConfigurer 和 org.mybatis.spring.SqlSessionFactoryBean的作用,可以直接看最后的總結

MapperFactoryBean是mapper接口的入口,它包含了sqlSessionFactory的封裝SqlSessionTemplate,而sqlSessionFactory又包含了mapper xml的組裝Configuration對象

從SqlSessionTemplate的

public <T> T getMapper(Class<T> type) {
return this.getConfiguration().getMapper(type, this);
}

開始,進入Configuration的getMapper(type,sqlsession)

public <T> T getMapper(Class<T> type, SqlSession sqlSession) {
return this.mapperRegistry.getMapper(type, sqlSession);
}

進入MapperRegistry

public <T> T getMapper(Class<T> type, SqlSession sqlSession) {
MapperProxyFactory mapperProxyFactory = (MapperProxyFactory)this.knownMappers.get(type);
if(mapperProxyFactory == null) {
throw new BindingException("Type " + type + " is not known to the MapperRegistry.");
} else {
try {
return mapperProxyFactory.newInstance(sqlSession);
} catch (Exception var5) {
throw new BindingException("Error getting mapper instance. Cause: " + var5, var5);
}
}
}

由MapperProxyFactory生成代理MapperProxy

protected T newInstance(MapperProxy<T> mapperProxy) {
return Proxy.newProxyInstance(this.mapperInterface.getClassLoader(), new Class[]{this.mapperInterface}, mapperProxy);
}

public T newInstance(SqlSession sqlSession) {
MapperProxy mapperProxy = new MapperProxy(sqlSession, this.mapperInterface, this.methodCache);
return this.newInstance(mapperProxy);
}

所以最終的調用會進入MapperProxy,接下來幾步在 mybatis緩存 中有介紹,會調用sqlSession(實際是SqlSessionTemplate)中的方法,看構造方法:

public SqlSessionTemplate(SqlSessionFactory sqlSessionFactory, ExecutorType executorType, PersistenceExceptionTranslator exceptionTranslator) {
        Assert.notNull(sqlSessionFactory, "Property \'sqlSessionFactory\' is required");
        Assert.notNull(executorType, "Property \'executorType\' is required");
        this.sqlSessionFactory = sqlSessionFactory;
        this.executorType = executorType;
        this.exceptionTranslator = exceptionTranslator;
        this.sqlSessionProxy = (SqlSession)Proxy.newProxyInstance(SqlSessionFactory.class.getClassLoader(), new Class[]{SqlSession.class}, new SqlSessionTemplate.SqlSessionInterceptor());
    }

會對SqlSessionFactory生成代理,實際調用這個代理的方法

public <T> T selectOne(String statement) {
return this.sqlSessionProxy.selectOne(statement);
}

1. 進入SqlSessionTemplate.SqlSessionInterceptor

public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
SqlSession sqlSession = SqlSessionUtils.getSqlSession(SqlSessionTemplate.this.sqlSessionFactory, SqlSessionTemplate.this.executorType, SqlSessionTemplate.this.exceptionTranslator);
   ......
Object t = method.invoke(sqlSession, args);
......
}

看SqlSessionUtils.getSqlSession方法:

public static SqlSession getSqlSession(SqlSessionFactory sessionFactory, ExecutorType executorType, PersistenceExceptionTranslator exceptionTranslator) {
        Assert.notNull(sessionFactory, "No SqlSessionFactory specified");
        Assert.notNull(executorType, "No ExecutorType specified");
        SqlSessionHolder holder = (SqlSessionHolder)TransactionSynchronizationManager.getResource(sessionFactory); if(holder != null && holder.isSynchronizedWithTransaction()) {
            if(holder.getExecutorType() != executorType) {
                throw new TransientDataAccessResourceException("Cannot change the ExecutorType when there is an existing transaction");
            } else {
                holder.requested();
                if(logger.isDebugEnabled()) {
                    logger.debug("Fetched SqlSession [" + holder.getSqlSession() + "] from current transaction");
                }

                return holder.getSqlSession();
            }
        } else {//進入這里呀呀呀 if(logger.isDebugEnabled()) {
                logger.debug("Creating a new SqlSession");
            }

       //step 1.1 SqlSession session
= sessionFactory.openSession(executorType); if(TransactionSynchronizationManager.isSynchronizationActive()) { Environment environment = sessionFactory.getConfiguration().getEnvironment(); if(environment.getTransactionFactory() instanceof SpringManagedTransactionFactory) { if(logger.isDebugEnabled()) { logger.debug("Registering transaction synchronization for SqlSession [" + session + "]"); }             //step 1.2 holder = new SqlSessionHolder(session, executorType, exceptionTranslator); TransactionSynchronizationManager.bindResource(sessionFactory, holder); TransactionSynchronizationManager.registerSynchronization(new SqlSessionUtils.SqlSessionSynchronization(holder, sessionFactory)); holder.setSynchronizedWithTransaction(true); holder.requested(); } else { if(TransactionSynchronizationManager.getResource(environment.getDataSource()) != null) { throw new TransientDataAccessResourceException("SqlSessionFactory must be using a SpringManagedTransactionFactory in order to use Spring transaction synchronization"); } if(logger.isDebugEnabled()) { logger.debug("SqlSession [" + session + "] was not registered for synchronization because DataSource is not transactional"); } } } else if(logger.isDebugEnabled()) { logger.debug("SqlSession [" + session + "] was not registered for synchronization because synchronization is not active"); } return session; } }

1.1 進入DefaultSqlSessionFactory openSession方法:

private SqlSession openSessionFromDataSource(ExecutorType execType, TransactionIsolationLevel level, boolean autoCommit) {
        Transaction tx = null;

        DefaultSqlSession var8;
        try {
            Environment e = this.configuration.getEnvironment();
//springManagedTransactionFactory TransactionFactory transactionFactory
= this.getTransactionFactoryFromEnvironment(e); tx = transactionFactory.newTransaction(e.getDataSource(), level, autoCommit); Executor executor = this.configuration.newExecutor(tx, execType, autoCommit); var8 = new DefaultSqlSession(this.configuration, executor); } catch (Exception var12) { this.closeTransaction(tx); throw ExceptionFactory.wrapException("Error opening session. Cause: " + var12, var12); } finally { ErrorContext.instance().reset(); } return var8; }

進入SpringManagedTransactionFactory的

newTransaction(e.getDataSource(), level, autoCommit);

返回

return new SpringManagedTransaction(dataSource);

這個SpringManagedTransaction比較特別,因為

private void openConnection() throws SQLException {
this.connection = DataSourceUtils.getConnection(this.dataSource);
this.autoCommit = this.connection.getAutoCommit();
this.isConnectionTransactional = DataSourceUtils.isConnectionTransactional(this.connection, this.dataSource);
if(this.logger.isDebugEnabled()) {
this.logger.debug("JDBC Connection [" + this.connection + "] will" + (this.isConnectionTransactional?" ":" not ") + "be managed by Spring");
}
}

因為它的連接來自DataSourceUtils

public static Connection doGetConnection(DataSource dataSource) throws SQLException {
        Assert.notNull(dataSource, "No DataSource specified");
        ConnectionHolder conHolder = (ConnectionHolder)TransactionSynchronizationManager.getResource(dataSource); if(conHolder == null || !conHolder.hasConnection() && !conHolder.isSynchronizedWithTransaction()) {
            logger.debug("Fetching JDBC Connection from DataSource");
            Connection con = dataSource.getConnection();
            if(TransactionSynchronizationManager.isSynchronizationActive()) {
                logger.debug("Registering transaction synchronization for JDBC Connection");
                ConnectionHolder holderToUse = conHolder;
                if(conHolder == null) {
                    holderToUse = new ConnectionHolder(con);
                } else {
                    conHolder.setConnection(con);
                }

                holderToUse.requested();
                TransactionSynchronizationManager.registerSynchronization(new DataSourceUtils.ConnectionSynchronization(holderToUse, dataSource));
                holderToUse.setSynchronizedWithTransaction(true);
                if(holderToUse != conHolder) {
                    TransactionSynchronizationManager.bindResource(dataSource, holderToUse);
                }
            }

            return con;
        } else {
            conHolder.requested();
            if(!conHolder.hasConnection()) {
                logger.debug("Fetching resumed JDBC Connection from DataSource");
                conHolder.setConnection(dataSource.getConnection());
            }

            return conHolder.getConnection();
        }
    }

這一步就和 spring--事務原理 中分析的對接了!!!connection連接對象來自當前線程綁定的ConnectionHolder中的connection對象

最終 DefaultSqlSession-》Executor-》Transaction-》當前線程綁定的ConnectionHolder中的connection對象 

1.2 構建SqlSessionHolder-》DefaultSqlSession,並綁定到當前線程<sessionFactory,session holder>

2. DefaultSqlSession的執行見  mybatis緩存 

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM