データベースのSqlSessionTemplateソースの解析


前言
一般的なJAVA-WEBプロジェクトの実際の業務処理では、最終的にはSqlSessionTemplateによってデータベースのCURD操作が実行される.本文はmybatisソースコードと結びつけて、SqlSessionTemplateについて詳しく紹介する.
SqlSessionTemplateは線称安全なクラスで、もしあなたのシステムがマイクロサービスアーキテクチャであれば、そのマイクロサービス(コンポーネント)の中のすべてのDAOは同じSqlSessionTemplateに対応するbeanインスタンスを共有することができます.SqlSessionTemplateはSqlSessionインタフェースを実装しているため、使用するSqlSessionが現在のSpringのトランザクションに関連していることを保証し、クローズ、コミット、ロールバック操作を含むsessionのライフサイクルを管理します.
では、彼が具体的にどのように実現したのか、ソースコードの解析を行います.
一、SqlSessionTemplateの初期化
まず、SqlSessionTemplateは初期化時にSqlSessionFactoryをパラメータとして入力します.
 
   
 

二、SqlSessionFactoryのプロキシクラスを作成する
ここで、SqlSessionTemplateインスタンスを初期化するときに、SqlSessionFactoryのプロキシクラスを作成することは、SqlSessionTemplateのプロパティの1つとしてキーです.
以下はmysqlソースコードです
1.エージェントの作成
public SqlSessionTemplate(SqlSessionFactory sqlSessionFactory, ExecutorType executorType,
      PersistenceExceptionTranslator exceptionTranslator) {
     

    notNull(sqlSessionFactory, "Property 'sqlSessionFactory' is required");
    notNull(executorType, "Property 'executorType' is required");

    this.sqlSessionFactory = sqlSessionFactory;
    this.executorType = executorType;
    this.exceptionTranslator = exceptionTranslator;
    //      sqlSession       ,             
    //        SqlSessionInterceptor invoke  
    this.sqlSessionProxy = (SqlSession) newProxyInstance(SqlSessionFactory.class.getClassLoader(),
        new Class[] {
      SqlSession.class }, new SqlSessionInterceptor());
  }

2.切面実装
エージェントを作成する目的は、フェースメソッドを実行することです.次に、フェース機能の詳細な解読を行います.
private class SqlSessionInterceptor implements InvocationHandler {
     
    @Override
    public Object invoke(Object proxy, Method method, Object[] args) 
            throws Throwable {
     
        //   SqlSession(  SqlSession       ,       )
        //   getSqlSession       ,        
        SqlSession sqlSession = getSqlSession(
                SqlSessionTemplate.this.sqlSessionFactory,
                SqlSessionTemplate.this.executorType,
                SqlSessionTemplate.this.exceptionTranslator);
        try {
     
            //    Spring          sqlSession
            //        (args) sqlSession,     sql  ,     
            Object result = method.invoke(sqlSession, args);
            //          sqlSession   Spring       Spring     commit
            if (!isSqlSessionTransactional(sqlSession, 
                    SqlSessionTemplate.this.sqlSessionFactory)) {
     
                // force commit even on non-dirty sessions because some databases require
                // a commit/rollback before calling close()
                sqlSession.commit(true);
            }
            return result;
        } catch (Throwable t) {
     
            //                 
            Throwable unwrapped = unwrapThrowable(t);
            if (SqlSessionTemplate.this.exceptionTranslator != null && 
                    unwrapped instanceof PersistenceException) {
     
                // release the connection to avoid a deadlock if the 
                // translator is no loaded. See issue #22
                closeSqlSession(sqlSession, SqlSessionTemplate.this.sqlSessionFactory);
                sqlSession = null;
                Throwable translated = SqlSessionTemplate.this.exceptionTranslator.
                        translateExceptionIfPossible((PersistenceException) unwrapped);
                if (translated != null) {
     
                    unwrapped = translated;
                }
            }
            throw unwrapped;
        } finally {
     
            if (sqlSession != null) {
     
                //   sqlSession     ,     sqlSession   Spring               
                //   sqlSession Spring  ,   holder.released(),    -1
                //          sqlSession
                closeSqlSession(sqlSession, SqlSessionTemplate.this.sqlSessionFactory);
            }
        }
    }
}

getSqlSessionメソッドは次のとおりです.
public static SqlSession getSqlSession(SqlSessionFactory sessionFactory, 
        ExecutorType executorType, PersistenceExceptionTranslator exceptionTranslator) {
     

    notNull(sessionFactory, NO_SQL_SESSION_FACTORY_SPECIFIED);
    notNull(executorType, NO_EXECUTOR_TYPE_SPECIFIED);

    //   sqlSessionFactory, TransactionSynchronizationManager     map 
    //          SqlSessionHolder
    SqlSessionHolder holder = (SqlSessionHolder) TransactionSynchronizationManager.
            getResource(sessionFactory);

    //  SqlSessionHolder   SqlSession  
    SqlSession session = sessionHolder(executorType, holder);
    if (session != null) {
     
        return session;
    }

    if (LOGGER.isDebugEnabled()) {
     
        LOGGER.debug("Creating a new SqlSession");
    }
    //       SqlSessionHolder   sqlSession,    sessionFactory     sqlSession
    session = sessionFactory.openSession(executorType);

    //      SqlSessionHolder,       sqlSession    
    //    SqlSessionHolder     TransactionSynchronizationManager 
    registerSessionHolder(sessionFactory, executorType, exceptionTranslator, session);

    return session;
}

まとめ
以上のように、SqlSessionTemplateのソースコードを解読することで、1つのマイクロサービス(コンポーネント)内のすべてのDAOが同じSqlSessionTemplateに対応するbeanインスタンスを共有し、スレッドの安全とトランザクションの完全性を保証できる理由を理解することができます.
1、複数のスレッドが同一のSqlSessionTemplateを呼び出してデータベース操作を行う場合、SqlSessionTemplateはエージェントメカニズムにより、毎回切面内のgetSqlSessionメソッドを実行して真の操作データベースのsqlSessionを取得する.
2.getSqlSessionメソッドでは、重要なTransactionSynchronizationManagerクラスが使用されている.このようにThreadLocal方式を利用して、現在のスレッドを一つのものにバインドすることで、現在のスレッドがsqlSessionを取得しようとしたときに、現在のスレッドにまだ完成していないものがあるかどうかを判断し、存在する場合には現在のものにバインドされたsqlSessionを利用してデータベース操作を実行する.存在しない場合は、新しいsqlSessionを作成して、スレッドのセキュリティとデータベース・事物の完全性を保証します.