<ruby id="bdb3f"></ruby>

    <p id="bdb3f"><cite id="bdb3f"></cite></p>

      <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
        <p id="bdb3f"><cite id="bdb3f"></cite></p>

          <pre id="bdb3f"></pre>
          <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

          <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
          <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

          <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                <ruby id="bdb3f"></ruby>

                企業??AI智能體構建引擎,智能編排和調試,一鍵部署,支持知識庫和私有化部署方案 廣告
                # (二):MySQL數據庫連接不夠用(TooManyConnections)問題的一次分析和解決案例 最近,項目中遇到了數據庫連接不夠的問題。 **異常信息** com.mysql.jdbc.exceptions.jdbc4.MySQLNonTransientConnectionException: ?Data source rejected establishment of connection,? message from server: "Too many connections" 根據更詳細的錯誤信息,我定位到報錯的函數位置。 **關鍵函數** ~~~ /**? ?*?判斷數據庫是否存在? ?*/?? public?boolean?hasDatabaseByKey(String?name)?{?? ?boolean?containsKey?=?dataSourceMap.containsKey(name);?? ?if?(containsKey)?{?? ?? ??try?{?? ??????//根據數據庫名稱,把BoneCP數據源中的數據庫參數取出來,用戶名、密碼、URL?? ???Object?obj?=?dataSourceMap.get(name);?? ???com.jolbox.bonecp.BoneCPDataSource?dataSource?=?(com.jolbox.bonecp.BoneCPDataSource)?obj;?? ?? ???String?password?=?dataSource.getPassword();?? ???String?username?=?dataSource.getUsername();?? ???String?url?=?dataSource.getJdbcUrl();?? ???//建立新的數據庫連接--這一行代碼拋出“Too?many?connections”異常?? ???Connection?con?=?DriverManager.getConnection(url,?username,?password);?? ???//關閉連接?? ???if?(con?!=?null)?{?? ????con.close();?? ???}?? ???return?true;?? ?? ??}?catch?(Exception?e)?{?? ???LOG.error("Database?name?error:"?+?name);?? ???e.printStackTrace();?? ??}?? ?}?? ?return?false;?? }?? ~~~ ? **是否正常關閉了數據庫連接** 上述代碼的主要功能是,根據前端傳入的數據庫名字,如“test”,檢測該數據庫的配置是否正確。 最初想到的,上面的數據庫連接con可能沒有正常關閉。 經過單步跟蹤debug,和使用MySQL的 show processlist命令,發現所有的連接確實是正常關閉的。 因此,上述代碼的功能是沒有問題的。 **功能沒有問題,但是上述代碼還是存在其它問題的** a.數據庫連接應該在finally里關閉。 b.這種檢測方法,每次都需要打開一個連接,比較耗費時間。 一種好的方法是,在系統初始化的時候,檢查所有的數據源配置是否正確,把結果 用Map保存起來,("test",true)表明test數據庫配置正確; 或者每一次檢查,先從緩存中取,如果存在直接使用,否則,打開連接,進行檢查,然后保存結果到緩存中。 **問題根源** 項目中使用了多個數據庫, 數據源公共的配置如下。 ~~~ <bean id="abstractDataSource" class="com.jolbox.bonecp.BoneCPDataSource" destroy-method="close"> <property name="username" value="root" /> <property name="password" value="xxxx" /> <property name="driverClass" value="com.mysql.jdbc.Driver"></property> <property name="maxConnectionsPerPartition" value="50"/> <property name="minConnectionsPerPartition" value="2"/> </bean> ~~~ **最近新增了10個數據源配置。** 也就是說,現在新增的數據庫連接,最高可以達到50*(10+1)=550個了。(不是50*1=50個) 而數據庫MySQL的默認max_connections是100。 因此,我們在訪問Web項目,然后頻繁切換項目的時候,數據庫連接池中的數目,已經達到了100。 這個時候,我們再去手動創建數據庫連接,就會失敗。 **上文代碼的更多配置信息** ~~~ @Resource?? private?Map?dataSourceMap;?? ~~~ ~~~ <!-- 配置多數據源映射關系 --> <bean id="dataSourceMap" class="java.util.HashMap"> <constructor-arg> <map key-type="java.lang.String"> <entry key="demo1"> <bean parent="abstractDataSource" > <property name="jdbcUrl" value="jdbc:mysql://ip:3306/demo1?useUnicode=true&characterEncoding=UTF-8&zeroDateTimeBehavior=convertToNull" /> </bean> </entry> <entry key="demo2"> <bean parent="abstractDataSource" > <property name="jdbcUrl" value="jdbc:mysql://ip:3306/demo2?useUnicode=true&characterEncoding=UTF-8&zeroDateTimeBehavior=convertToNull" /> </bean> </entry> </map> </constructor-arg> </bean> ~~~ **改進后的代碼** ~~~ private?static?Map?databaseStatusMap?=?new?HashMap();?? ??/**? ??*?判斷數據庫是否存在? ??*/?? ?public?boolean?hasDatabaseByKey(String?name)?{?? ??//數據源中是否含有這個數據庫名稱?? ??boolean?containsKey?=?dataSourceMap.containsKey(name);?? ??//不存在這個數據名字,直接false?? ??if?(!containsKey)?{?? ???return?false;?? ??}?? ?? ??//首先從緩存中拿,不為null,表明已經驗證過了?? ??Boolean?status=databaseStatusMap.get(name);?? ??if(status?!=?null){?? ???return?status;?? ??}?? ???? ??//緩存中不存在,第1次驗證?? ??boolean?databaseConfigSucceed?=?false;?? ??Connection?con?=?null;?? ??try?{?? ???Object?obj?=?dataSourceMap.get(name);?? ???com.jolbox.bonecp.BoneCPDataSource?dataSource?=?(com.jolbox.bonecp.BoneCPDataSource)?obj;?? ?? ???String?password?=?dataSource.getPassword();?? ???String?username?=?dataSource.getUsername();?? ???String?url?=?dataSource.getJdbcUrl();?? ?? ???//驗證數據庫連接,把結果存到緩存中?? ???con?=?DriverManager.getConnection(url,?username,?password);?? ????? ???//這個地方con不可能為null,要么是一個正常的連接,要么拋出異常?? ???databaseConfigSucceed?=?true;?? ???databaseStatusMap.put(name,?true);?? ???/*? ????if?(con?!=?null)?{? ????databaseConfigSucceed?=?true;? ????databaseStatusMap.put(name,?true);? ???}?? ???else{? ????databaseConfigSucceed?=?false;? ????databaseStatusMap.put(name,?false);? ???}*/?? ???? ??}?catch?(Exception?e)?{?? ???//拋出異常,下次不會去重新檢查,可能會存在bug,如果第1次檢測的時候,網斷了或者MySQL掛了或者數據庫連接過多,并不能代表配置不正確?? ???//小概率事件,暫時不考慮?? ???LOG.error("Database?name?error:"?+?name);?? ???databaseConfigSucceed=false;?? ???databaseStatusMap.put(name,?false);?? ???e.printStackTrace();?? ??}?finally?{?? ???if?(con?!=?null)?{?? ????try?{?? ?????//驗證完數據庫連接,需要手動關閉?? ?????con.close();?? ????}?catch?(SQLException?e)?{?? ?????e.printStackTrace();?? ????}?? ???}?? ??}?? ??return?databaseConfigSucceed;?? ?}?? ~~~ **小概率事件** 如果在執行?DriverManager.getConnection(url, username, password);獲取數據庫連接的時候,發生了異常。 如果恰好是第1次檢測的時候,網斷了或者MySQL掛了或者數據庫連接過多,并不能代表配置不正確。 拋出異常,下次就不會去重新檢查,可能會存在bug。 不過,系統第一次訪問項目的時候,正好出故障的可能性很低。 可能存在的錯誤情況: 第一次成功,加入緩存為true,如果今后數據庫連接打不開,應該提示“不可以打開”,也會提示“可以打開”。 第一次不成功,加入緩存為false,如果今后數據庫能夠打開,應該提示“可以打開”,也會提示“不可以打開”。 **結論** 1.在不使用緩存的情況下,每次都通過建立新連接的方式。 ?? 優點:可以準確的判斷數據庫配置是否正確,是否真正能夠連接到數據庫,代碼的可讀性和復雜度比較低。 ? 缺點:性能比較差。 2.使用緩存。 ?? 優點:性能比較高。 ?? 缺點:在不正常情況下,準確性沒有保障。代碼的可讀性和復雜度比較高。 **再次改進** 緩存,增加“時間限制”,過一段時間后,就失效。 **觀點** 實現的功能越多,越準確,性能越好,代碼可能會越來越復雜。 代碼的正確性和性能有的時候是“互相排斥”的。 過多的追求完美,也會帶來一些負擔。 **原文參見**:?[http://FansUnion.cn/articles/2961](http://fansunion.cn/articles/2961)
                  <ruby id="bdb3f"></ruby>

                  <p id="bdb3f"><cite id="bdb3f"></cite></p>

                    <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
                      <p id="bdb3f"><cite id="bdb3f"></cite></p>

                        <pre id="bdb3f"></pre>
                        <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

                        <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
                        <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

                        <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                              <ruby id="bdb3f"></ruby>

                              哎呀哎呀视频在线观看