mybatis與數據庫訪問相關的配置以及設計
mybatis與數據庫訪問相關的配置以及設計
mybatis不管如何NB,總是要與數據庫進行打交道。通過提問的方式,逐步深入
- 我們常用的MyBatis配置中哪些是與數據庫相關?
- 數據源配置:
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與數據庫訪問相關的配置以及設計