連接池
1.連接池是一個用來存儲連接的容器
2.連接池是一個集合對象,該集合必須是線程安全的,不能兩個線程拿到同一個連接
3.該集合實現隊列的特征:先進先出(在mybatis中實際上是ArrayList)

連接池在配置文件的位置
<environments default="mysql"> <environment id="mysql"> <transactionManager type="JDBC"></transactionManager> <dataSource type="POOLED">
有三種內建的數據源類型(也就是 type=”[UNPOOLED|POOLED|JNDI]”):
MyBatis 在初始化時, 根據<dataSource>的 type 屬性來創建相應類型的的數據源 DataSource,即:
type=”POOLED”: MyBatis 會創建 PooledDataSource 實例
type=”UNPOOLED” : MyBatis 會創建 UnpooledDataSource 實例
type=”JNDI”: MyBatis 會從 JNDI 服務上查找 DataSource 實例,然后返回使用

主要講一下:pooled與unpooled
MyBatis 內部分別定義了實現了 java.sql.DataSource 接口的 UnpooledDataSource,
PooledDataSource 類來表示 UNPOOLED、 POOLED 類型的數據源。
在這三種數據源中,我們一般采用的是 POOLED 數據源(很多時候我們所說的數據源就是為了更好的管理數據
庫連接,也就是我們所說的連接池技術) 。

追蹤unpooled
在idea中通過【ctrl + N】搜索【unpooleddatasource】,找到如下

貼一下jdbc中的執行步驟
//1.加載數據庫驅動 //Class.forName是把這個類加載到JVM中,加載的時候,就會執行其中的靜態初始化塊,完成驅動的初始化的相關工作。 Class.forName("com.mysql.jdbc.Driver"); //2.通過驅動管理類獲得數據庫連接a connection = DriverManager.getConnection ("jdbc:mysql://localhost:3306/cong","root","123456"); //3.定義sql語句 String sql = "select * from account where id = ?"; //4.獲得預處理statement preparedStatement = connection.prepareStatement(sql); //5.設置參數,第一個參數為 sql 語句中參數的序號(從 1 開始),第二個參數為設置的參數值 preparedStatement.setString(1, "1"); //6.執行操作 resultSet = preparedStatement.executeQuery(); //7.處理結果 while (resultSet.next()){ System.out.println("Account:"+resultSet.getInt("id") + "," + resultSet.getString("name")+ ","+resultSet.getFloat("money")); }
追蹤pooled
在idea中通過【ctrl + N】搜索【pooleddatasource】,找到如下

分析源代碼,得出 PooledDataSource 工作原理如下:

下面是獲取連接的源碼
@Override public Connection getConnection() throws SQLException { return popConnection(dataSource.getUsername(), dataSource.getPassword()).getProxyConnection(); } @Override public Connection getConnection(String username, String password) throws SQLException { return popConnection(username, password).getProxyConnection(); }
最后我們可以發現,真正連接打開的時間點,只是在我們執行SQL語句時,才會進行。其實這樣做我們也可以
進一步發現,數據庫連接是我們最為寶貴的資源,只有在要用到的時候,才去獲取並打開連接,當我們用完了就再
立即將數據庫連接歸還到連接池中
我們在實際開發中都會使用連接池。
因為它可以減少我們獲取連接所消耗的時間。
事務管理
mybatis中的事務是通過sqlsession對象的commit方法和rollback方法實現事務的提交和回滾
找到JdbcTransaction.java和SqlSessionFactory.java中的源碼,可以發現

於是,在我們的測試類中,可以這樣修改
當然,這個只能用於每次都僅僅執行一個對數據庫的crud操作的時候才可以用
像之前的轉賬操作,相當於在一個測試方法里面多次跟數據庫進行交互,
如果讓每個連接都處於獨立的自動提交,那這個事務肯定是控制不住的
spring中的轉賬傳送門:https://www.cnblogs.com/ccoonngg/p/11229393.html
@Before//在測試方法執行之前執行 public void init() throws Exception { //1.讀取配置文件,生成字節輸入流 inputStream = Resources.getResourceAsStream("SqlMapConfig.xml"); //2.獲取SqlSessionFactoryBuilder SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(inputStream); //3.生成sqlSession sqlSession = factory.openSession(true);//參數true表示自動提交 //4.獲取mapper的代理對象 mapper = sqlSession.getMapper(AccountMapper.class); } @After//在測試方法執行之后執行 public void close() throws Exception { //提交事務,增刪改需要提交事務,數據庫才會發生改變 //sqlSession.commit(); //釋放資源 sqlSession.close(); inputStream.close(); }
再運行一次,很明顯,自動提交了

我們發現,此時事務就設置為自動提交了,同樣可以實現CUD操作時記錄的保存。雖然這也是一種方式,但就
編程而言,設置為自動提交方式為 false 再根據情況決定是否進行提交,這種方式更常用。因為我們可以根據業務
情況來決定提交是否進行提交。
以下引用mybatis文檔
傳送門:http://www.mybatis.org/mybatis-3/zh/configuration.html#environments
事務管理器(transactionManager)
在 MyBatis 中有兩種類型的事務管理器(也就是 type=”[JDBC|MANAGED]”):
1.JDBC – 這個配置就是直接使用了 JDBC 的提交和回滾設置,它依賴於從數據源得到的連接來管理事務作用域。
2.MANAGED – 這個配置幾乎沒做什么。它從來不提交或回滾一個連接,而是讓容器來管理事務的整個生命周期(比如 JEE 應用服務器的上下文)。
默認情況下它會關閉連接,然而一些容器並不希望這樣,因此需要將 closeConnection 屬性設置為 false 來阻止它默認的關閉行為。例如:
<transactionManager type="MANAGED"> <property name="closeConnection" value="false"/> </transactionManager>
提示:如果你正在使用 Spring + MyBatis,則沒有必要配置事務管理器, 因為 Spring 模塊會使用自帶的管理器來覆蓋前面的配置。
這兩種事務管理器類型都不需要設置任何屬性。它們其實是類型別名,換句話說,你可以使用 TransactionFactory 接口的實現類的完全限定名或類型別名代替它們。
public interface TransactionFactory { default void setProperties(Properties props) { // Since 3.5.2, change to default method // NOP } Transaction newTransaction(Connection conn); Transaction newTransaction(DataSource dataSource, TransactionIsolationLevel level, boolean autoCommit); }
任何在 XML 中配置的屬性在實例化之后將會被傳遞給 setProperties() 方法。你也需要創建一個 Transaction 接口的實現類,這個接口也很簡單:
public interface Transaction { Connection getConnection() throws SQLException; void commit() throws SQLException; void rollback() throws SQLException; void close() throws SQLException; Integer getTimeout() throws SQLException; }
使用這兩個接口,你可以完全自定義 MyBatis 對事務的處理。
數據源(dataSource)
dataSource 元素使用標准的 JDBC 數據源接口來配置 JDBC 連接對象的資源。
許多 MyBatis 的應用程序會按示例中的例子來配置數據源。雖然這是可選的,但為了使用延遲加載,數據源是必須配置的。
有三種內建的數據源類型(也就是 type=”[UNPOOLED|POOLED|JNDI]”):
UNPOOLED– 這個數據源的實現只是每次被請求時打開和關閉連接。雖然有點慢,但對於在數據庫連接可用性方面沒有太高要求的簡單應用程序來說,是一個很好的選擇。 不同的數據庫在性能方面的表現也是不一樣的,對於某些數據庫來說,使用連接池並不重要,這個配置就很適合這種情形。UNPOOLED 類型的數據源具有以下屬性。:
- driver – 這是 JDBC 驅動的 Java 類的完全限定名(並不是 JDBC 驅動中可能包含的數據源類)。
- url – 這是數據庫的 JDBC URL 地址。
- username – 登錄數據庫的用戶名。
- password – 登錄數據庫的密碼。
- defaultTransactionIsolationLevel – 默認的連接事務隔離級別。
- defaultNetworkTimeout – 超時,毫秒數
作為可選項,你也可以傳遞屬性給數據庫驅動。只需在屬性名加上“driver.”前綴即可,例如:
- driver.encoding=UTF8
這將通過 DriverManager.getConnection(url,driverProperties) 方法傳遞值為 UTF8 的 encoding 屬性給數據庫驅動。
POOLED– 這種數據源的實現利用“池”的概念將 JDBC 連接對象組織起來,避免了創建新的連接實例時所必需的初始化和認證時間。 這是一種使得並發 Web 應用快速響應請求的流行處理方式。
除了上述提到 UNPOOLED 下的屬性外,還有更多屬性用來配置 POOLED 的數據源:
- poolMaximumActiveConnections – 在任意時間可以存在的活動(也就是正在使用)連接數量,默認值:10
- poolMaximumIdleConnections – 任意時間可能存在的空閑連接數。
- poolMaximumCheckoutTime – 在被強制返回之前,池中連接被檢出(checked out)時間,默認值:20000 毫秒(即 20 秒)
- poolTimeToWait – 這是一個底層設置,如果獲取連接花費了相當長的時間,連接池會打印狀態日志並重新嘗試獲取一個連接(避免在誤配置的情況下一直安靜的失敗),默認值:20000 毫秒(即 20 秒)。
- poolMaximumLocalBadConnectionTolerance – 這是一個關於壞連接容忍度的底層設置, 作用於每一個嘗試從緩存池獲取連接的線程。 如果這個線程獲取到的是一個壞的連接,那么這個數據源允許這個線程嘗試重新獲取一個新的連接,但是這個重新嘗試的次數不應該超過 poolMaximumIdleConnections 與 poolMaximumLocalBadConnectionTolerance 之和。 默認值:3 (新增於 3.4.5)
- poolPingQuery – 發送到數據庫的偵測查詢,用來檢驗連接是否正常工作並准備接受請求。默認是“NO PING QUERY SET”,這會導致多數數據庫驅動失敗時帶有一個恰當的錯誤消息。
- poolPingEnabled – 是否啟用偵測查詢。若開啟,需要設置 poolPingQuery 屬性為一個可執行的 SQL 語句(最好是一個速度非常快的 SQL 語句),默認值:false。
- poolPingConnectionsNotUsedFor – 配置 poolPingQuery 的頻率。可以被設置為和數據庫連接超時時間一樣,來避免不必要的偵測,默認值:0(即所有連接每一時刻都被偵測 — 當然僅當 poolPingEnabled 為 true 時適用)。
JNDI – 這個數據源的實現是為了能在如 EJB 或應用服務器這類容器中使用,容器可以集中或在外部配置數據源,然后放置一個 JNDI 上下文的引用。這種數據源配置只需要兩個屬性:
- initial_context – 這個屬性用來在 InitialContext 中尋找上下文(即,initialContext.lookup(initial_context))。這是個可選屬性,如果忽略,那么將會直接從 InitialContext 中尋找 data_source 屬性。
- data_source – 這是引用數據源實例位置的上下文的路徑。提供了 initial_context 配置時會在其返回的上下文中進行查找,沒有提供時則直接在 InitialContext 中查找。
和其他數據源配置類似,可以通過添加前綴“env.”直接把屬性傳遞給初始上下文。比如:
- env.encoding=UTF8
這就會在初始上下文(InitialContext)實例化時往它的構造方法傳遞值為 UTF8 的 encoding 屬性。
你可以通過實現接口 org.apache.ibatis.datasource.DataSourceFactory 來使用第三方數據源:
public interface DataSourceFactory { void setProperties(Properties props); DataSource getDataSource(); }
org.apache.ibatis.datasource.unpooled.UnpooledDataSourceFactory 可被用作父類來構建新的數據源適配器,比如下面這段插入 C3P0 數據源所必需的代碼:
import org.apache.ibatis.datasource.unpooled.UnpooledDataSourceFactory; import com.mchange.v2.c3p0.ComboPooledDataSource; public class C3P0DataSourceFactory extends UnpooledDataSourceFactory { public C3P0DataSourceFactory() { this.dataSource = new ComboPooledDataSource(); } }
為了令其工作,記得為每個希望 MyBatis 調用的 setter 方法在配置文件中增加對應的屬性。 下面是一個可以連接至 PostgreSQL 數據庫的例子:
<dataSource type="org.myproject.C3P0DataSourceFactory"> <property name="driver" value="org.postgresql.Driver"/> <property name="url" value="jdbc:postgresql:mydb"/> <property name="username" value="postgres"/> <property name="password" value="root"/> </dataSource>
