Spring+Mybatis 每次請求數據庫,爲什麼都會創建一個SqlSesssion?

先看一段代碼:

@Service
public class TblEmployeeServiceimpl implements TblEmployeeService {
    @Autowired
    private TblEmployeeMapper tblEmployeeMapper;
    @Override
    public TblEmployeePO select(Integer id) {
        TblEmployeePO tblEmployeePO=new  TblEmployeePO();
        tblEmployeePO = tblEmployeeMapper.selectByPrimaryKey(id);
        return tblEmployeePO;
    }
}
//jmeter測試: https://jingyan.baidu.com/article/eb9f7b6d52079d869364e825.html

每請求一次數據庫就創建一個SqlSession,這是爲啥呢?
在這裏插入圖片描述

容器啓動時:
Spring調用MapperFactoryBean.getObject()來生成Dao代理MapperyProxy分成如下兩步:getSqlSession()getMapper(this.mapperInterface)

public T getObject() throws Exception {
    return this.getSqlSession().getMapper(this.mapperInterface);
}

看看這個getSqlSession方法

SqlSessionDaoSupport類:
public SqlSession getSqlSession() {
   return this.sqlSessionTemplate;
}
//發現sqlSessionTemplate的值由createSqlSessionTemplate獲得
public void setSqlSessionFactory(SqlSessionFactory sqlSessionFactory) {
   if (this.sqlSessionTemplate == null || sqlSessionFactory != this.sqlSessionTemplate.getSqlSessionFactory()) {
       this.sqlSessionTemplate = this.createSqlSessionTemplate(sqlSessionFactory);
   }
}
//直接new了一個SqlSessionTemplate
protected SqlSessionTemplate createSqlSessionTemplate(SqlSessionFactory sqlSessionFactory) {
    return new SqlSessionTemplate(sqlSessionFactory);
}
SqlSessionTemplate類:一直跟進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());
 }

到最後,發現SqlSessionTemplate,有一個屬性SqlSession,是一個SqlSession的代理對象,SqlSessionTemplate本身也是一個SqlSession。並且在new SqlSessionTemplate的時候,通過構造函數給sqlSessionProxy 創建了一個sqlsession代理對象。

public class SqlSessionTemplate implements SqlSession, DisposableBean {
    private final SqlSessionFactory sqlSessionFactory;
    private final ExecutorType executorType;
    private final SqlSession sqlSessionProxy;
    private final PersistenceExceptionTranslator exceptionTranslator;

現在來看看創建sqlsession代理對象用到的攔截器SqlSessionInterceptorinvoke方法

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 unwrapped;
    try {
        Object result = method.invoke(sqlSession, args);
        if (!SqlSessionUtils.isSqlSessionTransactional(sqlSession, SqlSessionTemplate.this.sqlSessionFactory)) {
            sqlSession.commit(true);
        }
        unwrapped = result;
    } catch (Throwable var11) {
        unwrapped = ExceptionUtil.unwrapThrowable(var11);
        if (SqlSessionTemplate.this.exceptionTranslator != null && unwrapped instanceof PersistenceException) {
            SqlSessionUtils.closeSqlSession(sqlSession, SqlSessionTemplate.this.sqlSessionFactory);
            sqlSession = null;
            Throwable translated = SqlSessionTemplate.this.exceptionTranslator.translateExceptionIfPossible((PersistenceException)unwrapped);
            if (translated != null) {
                unwrapped = translated;
            }
        }
        throw (Throwable)unwrapped;
    } finally {
        if (sqlSession != null) {
            SqlSessionUtils.closeSqlSession(sqlSession, SqlSessionTemplate.this.sqlSessionFactory);
        }
    }
    return unwrapped;
}

過程:

  1. 進入請求,先生成一個新的sqlSession,爲本次db操作做準備;
  2. 通過反射調用請求進來的方法,將 sqlSession 回調,進行復雜查詢及結果映射;
  3. 如果需要立即提交事務,do it;
  4. 如果出現異常,包裝異常信息,重新拋出;
  5. 操作完成後,關閉本次session;

看第一步:SqlSessionUtils.getSqlSession,生成一個新的sqlSession

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);
    SqlSession session = sessionHolder(executorType, holder);
    if (session != null) {
        return session;
    } else {
        LOGGER.debug(() -> {
            return "Creating a new SqlSession";
        });
        //創建一個sqlsession
        session = sessionFactory.openSession(executorType);
        registerSessionHolder(sessionFactory, executorType, exceptionTranslator, session);
        return session;
    }
}

看到了熟悉的日誌 "Creating a new SqlSession",同時還創建了一個sqlsession


回到SqlSessionTemplate :可以看到SqlSessionTemplate的增刪改查實際上用的是sqlsession代理類。而使用代理類執行增刪改查,實際上就是執行代理類的invoke方法,而sqlsession代理類的invoke方法的第一步就是新建一個SqlSession。這些總算明白啦。
在這裏插入圖片描述

https://www.cnblogs.com/yougewe/p/10072740.html
https://blog.csdn.net/mayongzhan_csdn/article/details/78481987
https://www.xttblog.com/?p=4018

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章