• mybatis与数据库访问相关的配置以及设计


    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.");
                }
              }
            }
          }
    
        }

            

        

      

     

  • 相关阅读:
    vue-cli模拟后台数据交互
    打卡谱
    前端面试题
    ps简单切图
    常见浏览器兼容性问题与解决方案
    扯淡 测量体质公式 哈哈哈哈会不会封我号
    JAVASCRIPT 转换字符串杂记
    日记(六)
    gitshell 基础操作
    gitshell fork别人项目
  • 原文地址:https://www.cnblogs.com/marioS/p/10295203.html
Copyright © 2020-2023  润新知