1. 程式人生 > >mybatis與數據庫訪問相關的配置以及設計

mybatis與數據庫訪問相關的配置以及設計

bat inf shc led -a 失效 數據 bubuko invalid

mybatis與數據庫訪問相關的配置以及設計

mybatis不管如何NB,總是要與數據庫進行打交道。通過提問的方式,逐步深入

  • 我們常用的MyBatis配置中哪些是與數據庫相關?
  1. 數據源配置:
1         <environment id="development">
2             <transactionManager type="JDBC"/>
3             <dataSource type="POOLED">
4                 <property name="driver" value="${driver}"
/> 5 <property name="url" value="${url}"/> 6 <property name="username" value="${username}"/> 7 <property name="password" value="${password}"/> 8 </dataSource> 9 </environment>

看到這個配置文件,第一個直覺會想到由誰讀取配置文件,誰有讀取了配置信息?先忽略這個疑問,跳過。直接看下面的問題

  1.配置數據源信息後,由誰來創建、管理數據源?

    根據JDBC驅動中約束的接口,Connection需要DataSource中獲取

    如果自己設計,是否直接可以由工廠返回Connection?有什麽好處,有什麽壞處? //TODO

         沒看代碼前:

    技術分享圖片

        實際Mybatis設計,沒有直接返回Connection,而返回了dataSource

技術分享圖片

    2.對於有連接池的數據源,和無連接池的數據源,我們自己會如何設計?

      流程上的區別

技術分享圖片

     職責上區別

技術分享圖片

    現在解開謎底:看實際Mybatis設計如何?

      非池化類:

技術分享圖片

看下最關鍵的,獲得數據庫連接,和我們自己寫的沒啥區別。簡單粗暴

  private Connection doGetConnection(Properties properties) throws SQLException {
    initializeDriver();
    Connection connection = DriverManager.getConnection(url, properties);
    configureConnection(connection);
    return connection;
  }

    

    池化類:

    技術分享圖片

    池化工作分配 :


技術分享圖片

  至此,MYBABTIS對於數據源的創建以及管理結束!看下代碼,池化獲得連接的代碼

  @Override
  public Connection getConnection() throws SQLException {
    return popConnection(dataSource.getUsername(), dataSource.getPassword()).getProxyConnection();
  }

while (conn == null) { //夠用就行,拿到一個就返回
      synchronized (state) {

          //只有有連接還回來,再走這裏
        if (!state.idleConnections.isEmpty()) {
          // Pool has available connection
          conn = state.idleConnections.remove(0);
          if (log.isDebugEnabled()) {
            log.debug("Checked out connection " + conn.getRealHashCode() + " from pool.");
          }
        } else {

        //有兩種可能:1種,都在使用中,池子沒滿,再新建
          // Pool does not have available connection
          if (state.activeConnections.size() < poolMaximumActiveConnections) {
            // Can create new connection

            //新建連接
            conn = new PooledConnection(dataSource.getConnection(), this);
            if (log.isDebugEnabled()) {
              log.debug("Created connection " + conn.getRealHashCode() + ".");
            }
          } else {
            // Cannot create new connection

            //找一個最老的,用的ArrayList,老的在ArrayList數組的前面
            PooledConnection oldestActiveConnection = state.activeConnections.get(0);
            long longestCheckoutTime = oldestActiveConnection.getCheckoutTime();

            //借出超時,不讓他做了,直接rollback。。。暴力
            if (longestCheckoutTime > poolMaximumCheckoutTime) {
              // Can claim overdue connection
              state.claimedOverdueConnectionCount++;
              state.accumulatedCheckoutTimeOfOverdueConnections += longestCheckoutTime;
              state.accumulatedCheckoutTime += longestCheckoutTime;
              state.activeConnections.remove(oldestActiveConnection);
              if (!oldestActiveConnection.getRealConnection().getAutoCommit()) {
                try {
                  oldestActiveConnection.getRealConnection().rollback();
                } catch (SQLException e) {
                  /*
                     Just log a message for debug and continue to execute the following
                     statement like nothing happend.
                     Wrap the bad connection with a new PooledConnection, this will help
                     to not intterupt current executing thread and give current thread a
                     chance to join the next competion for another valid/good database
                     connection. At the end of this loop, bad {@link @conn} will be set as null.
                   */
                  log.debug("Bad connection. Could not roll back");
                }  
              }

              //拿回來後,不再放到原有的PooledConnection,新建立一個。從新開始.老的REAL connection還被oldestActiveConnection引用,不會內存溢出?
              conn = new PooledConnection(oldestActiveConnection.getRealConnection(), this);
              conn.setCreatedTimestamp(oldestActiveConnection.getCreatedTimestamp());
              conn.setLastUsedTimestamp(oldestActiveConnection.getLastUsedTimestamp());
              
              oldestActiveConnection.invalidate();
              if (log.isDebugEnabled()) {
                log.debug("Claimed overdue connection " + conn.getRealHashCode() + ".");
              }
            } else {
              // Must wait

                //大家都在用著,你只能等著了。
              try {
                if (!countedWait) {
                  state.hadToWaitCount++;
                  countedWait = true;
                }
                if (log.isDebugEnabled()) {
                  log.debug("Waiting as long as " + poolTimeToWait + " milliseconds for connection.");
                }
                long wt = System.currentTimeMillis();
                state.wait(poolTimeToWait);
                state.accumulatedWaitTime += System.currentTimeMillis() - wt;
              } catch (InterruptedException e) {
                break;
              }
            }
          }
        }
        if (conn != null) {
          // ping to server and check the connection is valid or not
          if (conn.isValid()) {
            if (!conn.getRealConnection().getAutoCommit()) {
              conn.getRealConnection().rollback();
            }
            conn.setConnectionTypeCode(assembleConnectionTypeCode(dataSource.getUrl(), username, password));
            conn.setCheckoutTimestamp(System.currentTimeMillis());
            conn.setLastUsedTimestamp(System.currentTimeMillis());
            state.activeConnections.add(conn);
            state.requestCount++;
            state.accumulatedRequestTime += System.currentTimeMillis() - t;
          } else {
            if (log.isDebugEnabled()) {
              log.debug("A bad connection (" + conn.getRealHashCode() + ") was returned from the pool, getting another connection.");
            }
            state.badConnectionCount++;
            localBadConnectionCount++;
            conn = null;

            //如果累計有這些個鏈接失效了,則報個異常.
            if (localBadConnectionCount > (poolMaximumIdleConnections + poolMaximumLocalBadConnectionTolerance)) {
              if (log.isDebugEnabled()) {
                log.debug("PooledDataSource: Could not get a good connection to the database.");
              }
              throw new SQLException("PooledDataSource: Could not get a good connection to the database.");
            }
          }
        }
      }

    }

        

    

  

mybatis與數據庫訪問相關的配置以及設計