日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

mybatis默认的数据源连接池(PooledDataSource和UnPooledDataSource)

發布時間:2024/9/15 编程问答 25 豆豆
生活随笔 收集整理的這篇文章主要介紹了 mybatis默认的数据源连接池(PooledDataSource和UnPooledDataSource) 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

一般情況下我們操作數據庫都是通過connection,但是頻繁創建和刪除connection會嚴重影響效率,因此在這種情況下我們一般會用到連接池,因為項目中用到的是mybatis,所以了解一下mybatis的默認的數據庫連接池(大多數情況下我們會使用Durid連接池)

代碼路徑:

很明顯看到datasource目錄下有pooled和unpooled兩個目錄,分別是使用到了連接池和沒有用到

1、unpooled目錄下的UnpooledDatasource.java

/*** @author Clinton Begin* @author Eduardo Macarron*/ public class UnpooledDataSource implements DataSource {private ClassLoader driverClassLoader;private Properties driverProperties;private static Map<String, Driver> registeredDrivers = new ConcurrentHashMap<String, Driver>();//常規配置private String driver;private String url;private String username;private String password;//是否自動commit 事務的隔離級別private Boolean autoCommit;private Integer defaultTransactionIsolationLevel;//注冊驅動static {Enumeration<Driver> drivers = DriverManager.getDrivers();while (drivers.hasMoreElements()) {Driver driver = drivers.nextElement();registeredDrivers.put(driver.getClass().getName(), driver);}}public UnpooledDataSource() {}public UnpooledDataSource(String driver, String url, String username, String password) {this.driver = driver;this.url = url;this.username = username;this.password = password;}//重點getconnnection 獲取數據庫連接,調用doGetConnection方法@Overridepublic Connection getConnection() throws SQLException {return doGetConnection(username, password);}@Overridepublic Connection getConnection(String username, String password) throws SQLException {return doGetConnection(username, password);}//用戶名 密碼 設置配置private Connection doGetConnection(String username, String password) throws SQLException {Properties props = new Properties();if (driverProperties != null) {props.putAll(driverProperties);}if (username != null) {props.setProperty("user", username);}if (password != null) {props.setProperty("password", password);}return doGetConnection(props);}//真正獲取連接的方法,由此可見,每次調用getConnection方法是,都會新建一個Connection對象,可想當并發量高是,數據庫的連接就會被占滿private Connection doGetConnection(Properties properties) throws SQLException {initializeDriver();Connection connection = DriverManager.getConnection(url, properties);configureConnection(connection);return connection;}//初始化 在調用doGetConnection方法中,會先進行一下判斷,判斷mybatis的configuration中是否已經有數據庫驅動,沒有的話會通過反射加載驅動private synchronized void initializeDriver() throws SQLException {if (!registeredDrivers.containsKey(driver)) {Class<?> driverType;try {if (driverClassLoader != null) {driverType = Class.forName(driver, true, driverClassLoader);} else {driverType = Resources.classForName(driver);}// DriverManager requires the driver to be loaded via the system ClassLoader.// http://www.kfu.com/~nsayer/Java/dyn-jdbc.htmlDriver driverInstance = (Driver)driverType.newInstance();DriverManager.registerDriver(new DriverProxy(driverInstance));registeredDrivers.put(driver, driverInstance);} catch (Exception e) {throw new SQLException("Error setting driver on UnpooledDataSource. Cause: " + e);}}}//設置是否自動提交 事務的隔離級別private void configureConnection(Connection conn) throws SQLException {if (autoCommit != null && autoCommit != conn.getAutoCommit()) {conn.setAutoCommit(autoCommit);}if (defaultTransactionIsolationLevel != null) {conn.setTransactionIsolation(defaultTransactionIsolationLevel);}}}

?

2、PolledDataSource.java類,其內部的datasource其實也是通過unpolledDataSource對象來實現的,只是在獲取連接connection的時候進行了處理(重點關注getConnection方法)

public class PooledDataSource implements DataSource {private static final Log log = LogFactory.getLog(PooledDataSource.class);//PollState 充當鎖對象,這個對象中也有例如 空閑連接集合,活躍鏈接集合,請求的數量,等一些變量private final PoolState state = new PoolState(this);//PolledDataSource中的數據源也是使用的UnpolledDataSource對象來實現的private final UnpooledDataSource dataSource;// OPTIONAL CONFIGURATION FIELDS 線程池的最大活躍數量,最大空閑數量,等待時間等等。。。protected int poolMaximumActiveConnections = 10;protected int poolMaximumIdleConnections = 5;protected int poolMaximumCheckoutTime = 20000;protected int poolTimeToWait = 20000;protected int poolMaximumLocalBadConnectionTolerance = 3;protected String poolPingQuery = "NO PING QUERY SET";protected boolean poolPingEnabled;protected int poolPingConnectionsNotUsedFor;//url+username+password連接起來的字符串的hashcode值private int expectedConnectionTypeCode;public PooledDataSource() {dataSource = new UnpooledDataSource();}public PooledDataSource(UnpooledDataSource dataSource) {this.dataSource = dataSource;}public PooledDataSource(String driver, String url, String username, String password) {dataSource = new UnpooledDataSource(driver, url, username, password);expectedConnectionTypeCode = assembleConnectionTypeCode(dataSource.getUrl(), dataSource.getUsername(), dataSource.getPassword());}//獲取連接connection@Overridepublic Connection getConnection() throws SQLException {return popConnection(dataSource.getUsername(), dataSource.getPassword()).getProxyConnection();}@Overridepublic Connection getConnection(String username, String password) throws SQLException {return popConnection(username, password).getProxyConnection();}//線程安全的獲取連接的方法(供PooledConnection中調用) synchronizedprotected void pushConnection(PooledConnection conn) throws SQLException {//所對象為PoolStatesynchronized (state) {state.activeConnections.remove(conn);if (conn.isValid()) {if (state.idleConnections.size() < poolMaximumIdleConnections && conn.getConnectionTypeCode() == expectedConnectionTypeCode) {state.accumulatedCheckoutTime += conn.getCheckoutTime();if (!conn.getRealConnection().getAutoCommit()) {conn.getRealConnection().rollback();}PooledConnection newConn = new PooledConnection(conn.getRealConnection(), this);state.idleConnections.add(newConn);newConn.setCreatedTimestamp(conn.getCreatedTimestamp());newConn.setLastUsedTimestamp(conn.getLastUsedTimestamp());conn.invalidate();if (log.isDebugEnabled()) {log.debug("Returned connection " + newConn.getRealHashCode() + " to pool.");}state.notifyAll();} else {state.accumulatedCheckoutTime += conn.getCheckoutTime();if (!conn.getRealConnection().getAutoCommit()) {conn.getRealConnection().rollback();}conn.getRealConnection().close();if (log.isDebugEnabled()) {log.debug("Closed connection " + conn.getRealHashCode() + ".");}conn.invalidate();}} else {if (log.isDebugEnabled()) {log.debug("A bad connection (" + conn.getRealHashCode() + ") attempted to return to the pool, discarding connection.");}state.badConnectionCount++;}}}private PooledConnection popConnection(String username, String password) throws SQLException {boolean countedWait = false;PooledConnection conn = null;long t = System.currentTimeMillis();int localBadConnectionCount = 0;while (conn == null) {synchronized (state) {//如果state中空閑的連接不為空時,直接從state中的idelConnections集合中獲取if (!state.idleConnections.isEmpty()) {// Pool has available connectionconn = state.idleConnections.remove(0);if (log.isDebugEnabled()) {log.debug("Checked out connection " + conn.getRealHashCode() + " from pool.");}} else {//state中的idelConnections集合中沒有連接connection了,判斷活躍的connection是否小于最大活躍線程數,小于的話就新建一個connection// Pool does not have available connection if (state.activeConnections.size() < poolMaximumActiveConnections) {// Can create new connectionconn = new PooledConnection(dataSource.getConnection(), this);if (log.isDebugEnabled()) {log.debug("Created connection " + conn.getRealHashCode() + ".");}} else {//當前活躍的connection數大于最大活躍connection數是,表明不能新建connection,這種情況下,會判斷是否已經超過設定的時間20s,如果超過,會根據是否自動commit,/不是自動提交,會進行rollback操作 // Cannot create new connectionPooledConnection oldestActiveConnection = state.activeConnections.get(0);long longestCheckoutTime = oldestActiveConnection.getCheckoutTime();if (longestCheckoutTime > poolMaximumCheckoutTime) {//判斷是否超時// Can claim overdue connectionstate.claimedOverdueConnectionCount++;state.accumulatedCheckoutTimeOfOverdueConnections += longestCheckoutTime;state.accumulatedCheckoutTime += longestCheckoutTime;state.activeConnections.remove(oldestActiveConnection);if (!oldestActiveConnection.getRealConnection().getAutoCommit()) {//判斷是否設置了自動提交,不是自動提交的話,會進行rollbacktry {oldestActiveConnection.getRealConnection().rollback();} catch (SQLException e) {/*Just log a message for debug and continue to execute the followingstatement like nothing happend.Wrap the bad connection with a new PooledConnection, this will helpto not intterupt current executing thread and give current thread achance to join the next competion for another valid/good databaseconnection. At the end of this loop, bad {@link @conn} will be set as null.*/log.debug("Bad connection. Could not roll back");} }//將之前rollback的connection進行處理,重新生成一個connection,并設置創建時間和最后使用時間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 {//當活躍connection的集合中第一個connection不符合超時,則進行等待wait// Must waittry {if (!countedWait) {state.hadToWaitCount++;countedWait = true;}//pooltimeTowait默認也是20秒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;}}}}//經過以上處理,如果conn仍然沒有值,則會循環走一行流程,第二次一定會獲取到conn對象(默認的超時時間是20秒,第一次已經等待過20s了)if (conn != null) {//判斷conn是否能用 通過ping能否ping通// ping to server and check the connection is valid or notif (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.");}}}}}if (conn == null) {if (log.isDebugEnabled()) {log.debug("PooledDataSource: Unknown severe error condition. The connection pool returned a null connection.");}throw new SQLException("PooledDataSource: Unknown severe error condition. The connection pool returned a null connection.");}return conn;} }

3、看下創建PooledConnection對象(從上邊截出的一部分代碼,新建PooledConnection對象)

// Pool does not have available connectionif (state.activeConnections.size() < poolMaximumActiveConnections) {// Can create new connectionconn = new PooledConnection(dataSource.getConnection(), this);if (log.isDebugEnabled()) {log.debug("Created connection " + conn.getRealHashCode() + ".");}}

PooledConnection構造函數:PooledConnection函數實現了InvocationHandler接口(動態代理)

public PooledConnection(Connection connection, PooledDataSource dataSource) {this.hashCode = connection.hashCode();this.realConnection = connection;this.dataSource = dataSource;this.createdTimestamp = System.currentTimeMillis();this.lastUsedTimestamp = System.currentTimeMillis();this.valid = true;this.proxyConnection = (Connection) Proxy.newProxyInstance(Connection.class.getClassLoader(), IFACES, this);}@Overridepublic Object invoke(Object proxy, Method method, Object[] args) throws Throwable {String methodName = method.getName();//判斷是否close,如果是close的話,會調用PooledDataSource中的pushConnection方法,將該conn從activeConnections刪除,同時將此conn添加到idelConnections中if (CLOSE.hashCode() == methodName.hashCode() && CLOSE.equals(methodName)) {dataSource.pushConnection(this);return null;} else {try {if (!Object.class.equals(method.getDeclaringClass())) {// issue #579 toString() should never fail// throw an SQLException instead of a RuntimecheckConnection();}return method.invoke(realConnection, args);} catch (Throwable t) {throw ExceptionUtil.unwrapThrowable(t);}}}

?

?

?

?

?

參考:https://blog.csdn.net/drxRose/article/details/85710850

https://www.jianshu.com/p/21cf094cb97b?open_source=weibo_search

?

與50位技術專家面對面20年技術見證,附贈技術全景圖

總結

以上是生活随笔為你收集整理的mybatis默认的数据源连接池(PooledDataSource和UnPooledDataSource)的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。