sql執(zhí)行過程分析

獲取sqlSession流程

  • new SqlSessionFactoryBuilder對象
  • sqlSessionFactoryBuilder對象new出一個XMLConfigBuilder對象,讀取mybatis-config.xml配置文件信息碱蒙,返回configuration
  • sqlsessionFactoryBuilder調(diào)用build(configuration方法)荠瘪,返回defaultSqlSessionFactory
  • sqlSessionFactory調(diào)用opensession方法,返回sqlSession
獲取sqlSession流程.png
  • openSessionFromDataSource源碼
    • 從配置中獲取Environment赛惩;
    • 從Environment中取得DataSource哀墓;
    • 從Environment中取得TransactionFactory;
    • 從DataSource里獲取數(shù)據(jù)庫連接對象Connection喷兼;
    • 在取得的數(shù)據(jù)庫連接上創(chuàng)建事務(wù)對象Transaction篮绰;
    • 創(chuàng)建Executor對象(該對象非常重要,事實上sqlsession的所有操作都是通過它完成的)褒搔;
    • 創(chuàng)建sqlsession對象阶牍;
/**
    * 通常一系列openSession方法最終都會調(diào)用本方法
    * @param execType 
    * @param level
    * @param autoCommit
    * @return
    */
 private SqlSession openSessionFromDataSource(ExecutorType execType, TransactionIsolationLevel level, boolean autoCommit) {
     Transaction tx = null;
     try {
         //通過Confuguration對象去獲取Mybatis相關(guān)配置信息, Environment對象包含了數(shù)據(jù)源和事務(wù)的配置
         final Environment environment = configuration.getEnvironment();
         final TransactionFactory transactionFactory = getTransactionFactoryFromEnvironment(environment);
         tx = transactionFactory.newTransaction(environment.getDataSource(), level, autoCommit);
         //之前說了喷面,從表面上來看,咱們是用sqlSession在執(zhí)行sql語句走孽,通過excutor執(zhí)行惧辈, excutor是對于Statement的封裝
         final Executor executor = configuration.newExecutor(tx, execType);
         //創(chuàng)建了一個DefaultSqlSession對象
         return new DefaultSqlSession(configuration, executor, autoCommit);
     } catch (Exception e) {
         closeTransaction(tx); // may have fetched a connection so lets call close()
         throw ExceptionFactory.wrapException("Error opening session.  Cause: " + e, e);
     } finally {
         ErrorContext.instance().reset();
     }
 }
  • MapperProxy分析


    mapperProxy獲取流程.png
  public <T> T getMapper(Class<T> type, SqlSession sqlSession) {
    //獲取代理工廠,在解析配置文件時磕瓷,會在knownMappers中放入key為Class<T>,value為代理工廠類對象
    final MapperProxyFactory<T> mapperProxyFactory = (MapperProxyFactory<T>) knownMappers.get(type);
    if (mapperProxyFactory == null) {
      throw new BindingException("Type " + type + " is not known to the MapperRegistry.");
    }
    try {
      return mapperProxyFactory.newInstance(sqlSession);
    } catch (Exception e) {
      throw new BindingException("Error getting mapper instance. Cause: " + e, e);
    }
  }
  protected T newInstance(MapperProxy<T> mapperProxy) {
    //jdk動態(tài)代理
    return (T) Proxy.newProxyInstance(mapperInterface.getClassLoader(), new Class[] { mapperInterface }, mapperProxy);
  }

  public T newInstance(SqlSession sqlSession) {
    //代理類
    final MapperProxy<T> mapperProxy = new MapperProxy<T>(sqlSession, mapperInterface, methodCache);
    return newInstance(mapperProxy);
  }
//代理類實現(xiàn) jdk動態(tài)代理接口
public class MapperProxy<T> implements InvocationHandler, Serializable {

  private static final long serialVersionUID = -6424540398559729838L;
  private final SqlSession sqlSession;
  private final Class<T> mapperInterface;
  private final Map<Method, MapperMethod> methodCache;

  public MapperProxy(SqlSession sqlSession, Class<T> mapperInterface, Map<Method, MapperMethod> methodCache) {
    this.sqlSession = sqlSession;
    this.mapperInterface = mapperInterface;
    this.methodCache = methodCache;
  }

  @Override
  public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
    if (Object.class.equals(method.getDeclaringClass())) {
      try {
        return method.invoke(this, args);
      } catch (Throwable t) {
        throw ExceptionUtil.unwrapThrowable(t);
      }
    }
    //通過MapperMethod來真正的實現(xiàn)增刪改查功能
    final MapperMethod mapperMethod = cachedMapperMethod(method);
    //執(zhí)行增刪改查
    return mapperMethod.execute(sqlSession, args);
  }

  private MapperMethod cachedMapperMethod(Method method) {
    MapperMethod mapperMethod = methodCache.get(method);
    if (mapperMethod == null) {
      mapperMethod = new MapperMethod(mapperInterface, method, sqlSession.getConfiguration());
      methodCache.put(method, mapperMethod);
    }
    return mapperMethod;
  }

}
  • excutor分析
  public Object execute(SqlSession sqlSession, Object[] args) {
    Object result;
    //根據(jù)不同的sqlCommandType類型盒齿,以及不同的返回類型,調(diào)用不同的方法
    if (SqlCommandType.INSERT == command.getType()) {
      Object param = method.convertArgsToSqlCommandParam(args);
      result = rowCountResult(sqlSession.insert(command.getName(), param));
    } else if (SqlCommandType.UPDATE == command.getType()) {
      Object param = method.convertArgsToSqlCommandParam(args);
      result = rowCountResult(sqlSession.update(command.getName(), param));
    } else if (SqlCommandType.DELETE == command.getType()) {
      Object param = method.convertArgsToSqlCommandParam(args);
      result = rowCountResult(sqlSession.delete(command.getName(), param));
    } else if (SqlCommandType.SELECT == command.getType()) {
      if (method.returnsVoid() && method.hasResultHandler()) {
        executeWithResultHandler(sqlSession, args);
        result = null;
      } else if (method.returnsMany()) {
        result = executeForMany(sqlSession, args);
      } else if (method.returnsMap()) {
        result = executeForMap(sqlSession, args);
      } else {
        Object param = method.convertArgsToSqlCommandParam(args);
        result = sqlSession.selectOne(command.getName(), param);
      }
    } else if (SqlCommandType.FLUSH == command.getType()) {
        result = sqlSession.flushStatements();
    } else {
      throw new BindingException("Unknown execution method for: " + command.getName());
    }
    if (result == null && method.getReturnType().isPrimitive() && !method.returnsVoid()) {
      throw new BindingException("Mapper method '" + command.getName() 
          + " attempted to return null from a method with a primitive return type (" + method.getReturnType() + ").");
    }
    return result;
  }
 @Override
  public <E> List<E> selectList(String statement, Object parameter, RowBounds rowBounds) {
    try {
      //獲取mapperStatement信息
      MappedStatement ms = configuration.getMappedStatement(statement);
      return executor.query(ms, wrapCollection(parameter), rowBounds, Executor.NO_RESULT_HANDLER);
    } catch (Exception e) {
      throw ExceptionFactory.wrapException("Error querying database.  Cause: " + e, e);
    } finally {
      ErrorContext.instance().reset();
    }
  }
  //最終會調(diào)用這個方法中
  public <E> List<E> doQuery(MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler, BoundSql boundSql) throws SQLException {
    Statement stmt = null;
    try {
      Configuration configuration = ms.getConfiguration();
      //獲取statement代理對象   并且或創(chuàng)建resultehander代理對象
      StatementHandler handler = configuration.newStatementHandler(wrapper, ms, parameter, rowBounds, resultHandler, boundSql);
      stmt = prepareStatement(handler, ms.getStatementLog());
      return handler.<E>query(stmt, resultHandler);
    } finally {
      closeStatement(stmt);
    }
  }
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末困食,一起剝皮案震驚了整個濱河市边翁,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌硕盹,老刑警劉巖符匾,帶你破解...
    沈念sama閱讀 217,734評論 6 505
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異瘩例,居然都是意外死亡啊胶,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,931評論 3 394
  • 文/潘曉璐 我一進店門垛贤,熙熙樓的掌柜王于貴愁眉苦臉地迎上來焰坪,“玉大人,你說我怎么就攤上這事聘惦∧呈危” “怎么了?”我有些...
    開封第一講書人閱讀 164,133評論 0 354
  • 文/不壞的土叔 我叫張陵善绎,是天一觀的道長黔漂。 經(jīng)常有香客問我,道長涂邀,這世上最難降的妖魔是什么瘟仿? 我笑而不...
    開封第一講書人閱讀 58,532評論 1 293
  • 正文 為了忘掉前任,我火速辦了婚禮比勉,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘驹止。我一直安慰自己浩聋,他們只是感情好,可當我...
    茶點故事閱讀 67,585評論 6 392
  • 文/花漫 我一把揭開白布臊恋。 她就那樣靜靜地躺著衣洁,像睡著了一般。 火紅的嫁衣襯著肌膚如雪抖仅。 梳的紋絲不亂的頭發(fā)上坊夫,一...
    開封第一講書人閱讀 51,462評論 1 302
  • 那天砖第,我揣著相機與錄音,去河邊找鬼环凿。 笑死梧兼,一個胖子當著我的面吹牛,可吹牛的內(nèi)容都是我干的智听。 我是一名探鬼主播羽杰,決...
    沈念sama閱讀 40,262評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼到推!你這毒婦竟也來了考赛?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 39,153評論 0 276
  • 序言:老撾萬榮一對情侶失蹤莉测,失蹤者是張志新(化名)和其女友劉穎颜骤,沒想到半個月后,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體捣卤,經(jīng)...
    沈念sama閱讀 45,587評論 1 314
  • 正文 獨居荒郊野嶺守林人離奇死亡忍抽,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,792評論 3 336
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了腌零。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片梯找。...
    茶點故事閱讀 39,919評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖益涧,靈堂內(nèi)的尸體忽然破棺而出锈锤,到底是詐尸還是另有隱情,我是刑警寧澤闲询,帶...
    沈念sama閱讀 35,635評論 5 345
  • 正文 年R本政府宣布久免,位于F島的核電站,受9級特大地震影響扭弧,放射性物質(zhì)發(fā)生泄漏阎姥。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 41,237評論 3 329
  • 文/蒙蒙 一鸽捻、第九天 我趴在偏房一處隱蔽的房頂上張望呼巴。 院中可真熱鬧,春花似錦御蒲、人聲如沸衣赶。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,855評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽府瞄。三九已至,卻和暖如春碘箍,著一層夾襖步出監(jiān)牢的瞬間遵馆,已是汗流浹背鲸郊。 一陣腳步聲響...
    開封第一講書人閱讀 32,983評論 1 269
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留货邓,地道東北人秆撮。 一個月前我還...
    沈念sama閱讀 48,048評論 3 370
  • 正文 我出身青樓,卻偏偏與公主長得像逻恐,于是被迫代替她去往敵國和親像吻。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 44,864評論 2 354

推薦閱讀更多精彩內(nèi)容

  • 前面的章節(jié)主要講mybatis如何解析配置文件复隆,這些都是一次性的初始化過程拨匆。從本章開始講解動態(tài)的過程,它們跟應(yīng)用程...
    七寸知架構(gòu)閱讀 4,940評論 2 55
  • 1 緩存介紹# MyBatis支持聲明式數(shù)據(jù)緩存(declarative data caching)挽拂。當一條SQL...
    七寸知架構(gòu)閱讀 2,124評論 2 51
  • 1. 簡介 1.1 什么是 MyBatis 惭每? MyBatis 是支持定制化 SQL、存儲過程以及高級映射的優(yōu)秀的...
    笨鳥慢飛閱讀 5,520評論 0 4
  • 1 引言# 本文主要講解JDBC怎么演變到Mybatis的漸變過程亏栈,重點講解了為什么要將JDBC封裝成Mybait...
    七寸知架構(gòu)閱讀 76,465評論 36 980
  • Spring Cloud為開發(fā)人員提供了快速構(gòu)建分布式系統(tǒng)中一些常見模式的工具(例如配置管理台腥,服務(wù)發(fā)現(xiàn),斷路器绒北,智...
    卡卡羅2017閱讀 134,656評論 18 139