当前位置: 代码迷 >> SQL >> Mybatis深入剖解 - SqlSession的初始化分析
  详细解决方案

Mybatis深入剖解 - SqlSession的初始化分析

热度:93   发布时间:2016-05-05 10:55:22.0
Mybatis深入剖析 - SqlSession的初始化分析

SqlSession的初始化

  • ? ? 声明周期-SqlSession为回话声明周期,理论上一次用户请求,即一个线程里只开启一次session,使 ? ? ? 用后即关闭
  • ? ? 依赖-DefaultSqlSessionFactory为SqlSesson的工场类,看下面的代码,即可知道Configuration, ? ? ? ? Executor和Connection为它所依赖对象
private SqlSession openSessionFromConnection(ExecutorType execType, Connection connection) {    try {      boolean autoCommit;      try {        autoCommit = connection.getAutoCommit();      } catch (SQLException e) {        // Failover to true, as most poor drivers        // or databases won't support transactions        autoCommit = true;      }      connection = wrapConnection(connection);      final Environment environment = configuration.getEnvironment();      final TransactionFactory transactionFactory = getTransactionFactoryFromEnvironment(environment);      Transaction tx = transactionFactory.newTransaction(connection, autoCommit);      Executor executor = configuration.newExecutor(tx, execType);      return new DefaultSqlSession(configuration, executor, autoCommit);    } catch (Exception e) {      throw ExceptionFactory.wrapException("Error opening session.  Cause: " + e, e);    } finally {      ErrorContext.instance().reset();    }  }

?

  • 如何使用:

? ? 原始的使用方式如下,一个线程里的所有数据库操作方法中都需要新开启Session,浪费资源

SqlSession session= sqlSessionFactory.openSession();UserDao userDao = session.getMapper(UserDao.class);UserVo vo = new UserVo();vo.setName("a");List<UserVo> users = userDao.queryUsers(user);

? ?

? ? 那我们来看看Spring是如何管理SqlSession的,SqlSessonUtils中获取Session的方法如下,*注解的代码是获取session的核心,其本质是ThreadLocal绑定资源到当前线程上,

 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");            }            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(sessionFactory, holder);            TransactionSynchronizationManager.registerSynchronization(new SqlSessionSynchronization(holder, sessionFactory));            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;    }

?

以上代码总结起来, 主要有以下两点

  1. SessionHolder为SqlSession,ExecutorType和ExceptionTranslator的包装类
  2. ?以SessionFactory为key,在Thread声明周期里缓存SessionHold

具体Spring trasaction的内部解析请见另一片博客

?

?

? ??

  相关解决方案