淺談Mybatis鏈接原理

       衆所周知數據庫鏈接的過程,可是最近面試的人(菜面菜),都說用的SSM框架,可是我問了一下,mybatis是怎麼鏈接上mysql的,基本上都會說:配置好的,直接用了,今天我來拋磚引玉一下,歡迎拍磚!java

       什麼是JDBC?mysql

       Java語言訪問數據庫的一種規範,是一套API。JDBC (Java Database Connectivity) API,即Java數據庫編程接口,是一組標準的Java語言中的接口和類,使用這些接口和類,Java客戶端程序能夠訪問各類不一樣類型的數據庫。JDBC規範採用接口和實現分離的思想設計了Java數據庫編程的框架。接口包含在java.sql及javax.sql包中,其中java.sql屬於JavaSE,javax.sql屬於JavaEE。爲了使客戶端程序獨立於特定的數據庫驅動程序,JDBC規範建議開發者使用基於接口的編程方式,即儘可能使應用僅依賴java.sql及javax.sql中的接口和類。面試

        JAVA使用JDBC訪問數據庫的步驟:spring

        1.獲得數據庫驅動程序sql

        2.建立數據庫鏈接數據庫

        3.執行SQL語句編程

        4.獲得結果集設計模式

        5.對結果集作相應的處理(增,刪,改,查)api

        6.關閉資源:這裏釋放的是DB中的資源session

        mysql的驅動包提供了java.sql.Driver這個SPI的實現,實現類是com.mysql.jdbc.Driver,在mysql-connector-java-5.1.6.jar中,咱們能夠看到有一個META-INF/services目錄,目錄下有一個文件名爲java.sql.Driver的文件,其中的內容是com.mysql.jdbc.Driver。
在運行DriverManager.getDriver並傳入參數「com.mysql.jdbc.Driver」時,DriverManager會從mysql-connector-java-5.1.6.jar中找到com.mysql.jdbc.Driver並實例化返回一個com.mysql.jdbc.Driver的實例。而SPI(Service Provider Interface)是指一些提供給你繼承、擴展,完成自定義功能的類、接口或者方法。

       SPI是一種回調的思想,回調是指咱們在使用api時,咱們能夠向API傳入一個類或者方法,API在合適的時間調用類或者方法。SPI是在一些通用的標準中,爲標準的實現產商提供的擴展點。標準在上層提供API,API內部使用了SPI,當API被客戶使用時,會動態得從當前運行的classpath中尋找該SPI的實現,而後使用該SPI的實現來完成API的功能。
       SPI的實現方式是:提供實現的實現類打包成Jar文件,這個Jar文件裏面必須有META-INF目錄,其下又有services目錄,其下有一個文本文件,文件名即爲SPI接口的全名,文件的內容該jar包中提供的SPI接口的實現類名。
       你們看項目中Mybaits的jar包會發現:
private class SqlSessionInterceptor implements InvocationHandler {
    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
      SqlSession sqlSession = getSqlSession(
          SqlSessionTemplate.this.sqlSessionFactory,
          SqlSessionTemplate.this.executorType,
          SqlSessionTemplate.this.exceptionTranslator);
      try {
        Object result = method.invoke(sqlSession, args);
        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) {
          closeSqlSession(sqlSession, SqlSessionTemplate.this.sqlSessionFactory);
        }
      }
    }
  }

      sqlSessionTemplate.SqlSessionInterceptor源碼,有沒有一種很熟悉的感受?至於getConnection本身去看;用過ElasticSearch和Redis的童鞋,細心的童鞋會發現鏈接字符串都大同小異,鏈接都是相似的,標準的鏈接方式,提升效率,有效控制鏈接;

      ElasticSearch的鏈接字符串:

protected SearchResponse getSearchResponse(String fieldName, String indexName) {
    client = null;
    SearchResponse response = null;
    try {
        getClient();
        MaxAggregationBuilder aggregation =
                AggregationBuilders
                        .max("agg")
                        .field(fieldName);
        SearchRequestBuilder request = client.prepareSearch(indexName).addAggregation(aggregation);
        response = request.execute().actionGet();
    } catch (Exception ex) {
        logger.error("getSearchResponse", ex);
    } finally {
        if (client != null) {
            client.close();
        }
        return response;
    }
}

     Jedis鏈接字符串:

執行命令以下:
Jedis jedis = null;
try {
    jedis = jedisPool.getResource();
    //具體的命令
    jedis.executeCommand()
} catch (Exception e) {
    logger.error("op key {} error: " + e.getMessage(), key, e);
} finally {
    //注意這裏不是關閉鏈接,在JedisPool模式下,Jedis會被歸還給資源池。
    if (jedis != null) 
        jedis.close(); 
}

       攔截器的實現都是基於代理的設計模式實現的,簡單的說就是要創造一個目標類的代理類,在代理類中執行目標類的方法並在方法以前執行攔截器代碼,攔截器通常有登錄攔截器——驗證會話信息,權限攔截器——驗證權限信息,那麼SqlSessionInterceptor是幹什麼的?

       Mybatis攔截器設計的一個初衷就是爲了供用戶在某些時候能夠實現本身的邏輯而沒必要去動Mybatis固有的邏輯。打個比方,對於Executor,Mybatis中有幾種實現:BatchExecutor、ReuseExecutor、SimpleExecutor和CachingExecutor。
這個時候若是你以爲這幾種實現對於Executor接口的query方法都不能知足你的要求,那怎麼辦呢?是要去改源碼嗎?固然不。咱們能夠創建一個Mybatis攔截器用於攔截Executor接口的query方法,在攔截以後實現本身的query方法邏輯,以後能夠選擇是否繼續執行原來的query方法。容許你在已映射語句執行過程當中的某一點進行攔截調用。有的用Mybatis攔截器統封裝分頁,有的用它實現讀寫分離等,若是讀寫分離仍是建議配置多數據源;

       spring整合mybatis以後,經過動態代理的方式,使用SqlSessionTemplate持有的sqlSessionProxy屬性來代理執行sql操做,由spring管理的sqlSeesion在sql方法(增刪改查等操做)執行完畢後就自行關閉了sqlSession,不須要咱們對其進行手動關閉。

       願你有情人終成眷屬,願你有個有趣的靈魂,願你拍我一磚!

相關文章
相關標籤/搜索