mybatis中的鏈接池
關於連接池
對於鏈接池,大家應該都不陌生,工程中不免存在許多需要訪問數據的請求(訪問服務、數據庫、緩存等),對於這些下游服務,官方會提供不同語言的Driver、Document、DemoCode來指導使用方建立連接與接口調用。基本的通訊步驟爲:建立連接、發送請求、關閉連接釋放資源。對於併發量很低的請求,連接可以臨時建立,但是當服務吞吐量非常大,建立連接connect和銷燬連接close就會成爲瓶頸,爲了對其進行優化,連接池出現了。
通過鏈接池,請求的通訊步驟變爲:從池中取出鏈接、發送請求、放回鏈接。
連接池核心原理與實現
數據庫操作僞代碼
DBClientConnection* c = ConnectionPool::GetConnection();
c->insert(“db.s”, BSON(”shenjian”));
ConnectionPool::FreeConnection(c);
可以看到連接池ConnectionPool主要有三個核心接口:
(1)Init:初始化Array[DBClientConnection],這個接口只在服務啓動時調用一次;
(2)GetConnection:請求每次需要訪問數據庫時,不connect一個新連接,而是通過連接池的這個接口來拿連接;
(3)FreeConnection:請求每次訪問完數據庫時,不是close一個連接,而是把這個連接放回連接池;
通俗的講,連接池就是用於存儲鏈接的一個容器,容器其實就是一個集合對象,並且該集合必須是線程安全的,不能兩個線程拿到同一個鏈接。該集合還必須實現隊列的特性,先進先出。
mybatis中的鏈接池
幾種連接池介紹
在mybatis中,含有以下幾類連接池:
pooled:採用傳統的javax.sql.DataSource規範中的連接池,mybatis中有針對規範的實現。
unpooled:採用傳統的獲取連接的方式,雖然也實現javax.sql.DataSource接口,但是並沒有使用池的思想。
jndi:採用服務器提供的jndi技術實現,來獲取DataSource對象,不同的服務器所能拿到的DataSource是不一樣的。
在這三種數據源中,我們一般採用的是 POOLED 數據源。
mybatis中連接池配置
在 Mybatis 的 SqlMapConfig.xml 配置文件中,通過來實現 Mybatis 中連接池的配置。type屬性就是表示採用何種鏈接池方式。
<!-- 配置數據源(連接池)信息 -->
<dataSource type="POOLED">
<property name="driver" value="com.mysql.jdbc.Driver"/>
<property name="url" value="jdbc:mysql://localhost:3306/mybatis"/>
<property name="username" value="root"/>
<property name="password" value="1234"/>
</dataSource>
當然如果配置了properties標籤,可以進行連接信息的抽離:
<properties resource="dbconfig.properties"></properties>
<environments default="development">
<environment id="development">
<transactionManager type="JDBC"/>
<dataSource type="POOLED">
<property name="driver" value="${jdbc.driver}"/>
<property name="url" value="${jdbc.url}"/>
<property name="username" value="${jdbc.username}"/>
<property name="password" value="${jdbc.password}"/>
</dataSource>
</environment>
</environments>
MyBatis 在初始化時,根據的 type 屬性來創建相應類型的的數據源 DataSource,即:type=”POOLED”:MyBatis 會創建 PooledDataSource 實例,然後返回使用。
MyBatis 是通過工廠模式來創建數據源 DataSource 對象的, MyBatis 定義了抽象的工廠接口:org.apache.ibatis.datasource.DataSourceFactory,通過其 getDataSource()方法返回數據源DataSource。
//DataSourceFactory源碼
package org.apache.ibatis.datasource;
import java.util.Properties;
import javax.sql.DataSource;
/**
* @author Clinton Begin
*/
public interface DataSourceFactory {
void setProperties(Properties props);
DataSource getDataSource();
}
MyBatis 創建了 DataSource 實例後,會將其放到 Configuration 對象內的 Environment 對象中, 供以後使用。
當我們需要創建 SqlSession 對象並需要執行 SQL 語句時,這時候 MyBatis 纔會去調用 dataSource 對象來創建java.sql.Connection對象。也就是說,java.sql.Connection對象的創建一直延遲到執行SQL語句的時候。
@Test
public void testSql() throws Exception {
InputStream in = Resources.getResourceAsStream("SqlMapConfig.xml");
SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(in);
SqlSession sqlSession = factory.openSession();
List<User> list = sqlSession.selectList("findUserById",41);
System.out.println(list.size());
}
只有當第 4 句sqlSession.selectList(“findUserById”),纔會觸發 MyBatis 在底層執行下面這個方法來創建 java.sql.Connection 對象。
數據庫連接是我們最爲寶貴的資源,只有在要用到的時候,纔去獲取並打開連接,當我們用完了就再立即將數據庫連接歸還到連接池中。
mybatis中的事務
對於增刪改操作,並不是讀到語句後就立馬對數據庫數據進行更新,而是通過建立連接,每建立一次連接,並且這些操作在同一個連接內,那麼在語句執行完畢後,這些增刪改操作將會被一起提交到數據庫中執行。
而對於select語句,在語句關聯結果集關閉時,也就是本條查詢語句已經明確將查詢結果付給什麼變量時,就會向數據庫中提交一次執行。
以上這些是JDBC的默認提交時間。
在 JDBC 中我們可以自行將事務的提交改爲手動方式,通過setAutoCommit()方法就可以調整。也就是當我們在新建立連接時,可以根據傳入參數的不同,說明本次連接時自動提交還是手動提交。
那麼我們的 Mybatis 框架因爲是對 JDBC 的封裝,所以 Mybatis 框架的事務控制方式,本身也是用 JDBC的setAutoCommit()方法來設置事務提交方式的。
Mybatis 手動提交事務
@Test
public void testSaveUser() throws Exception {
User user = new User();
user.setUsername("mybatis user09");
//6.執行操作
int res = userDao.saveUser(user);
System.out.println(res);
System.out.println(user.getId());
}
@Before//在測試方法執行之前執行
public void init()throws Exception {
//1.讀取配置文件
in = Resources.getResourceAsStream("SqlMapConfig.xml");
//2.創建構建者對象
SqlSessionFactoryBuilder builder = new SqlSessionFactoryBuilder();
//3.創建 SqlSession 工廠對象
factory = builder.build(in);
//4.創建 SqlSession 對象
session = factory.openSession();
//5.創建 Dao 的代理對象
userDao = session.getMapper(IUserDao.class);
}
@After//在測試方法執行完成之後執行
public void destroy() throws Exception{
//7.提交事務
session.commit();
//8.釋放資源
session.close();
in.close();
}
以上在創建連接時:session=factory.openSession();沒有傳入參數,這樣一來連接池中取出的連接,都會將調用 connection.setAutoCommit(false)方法,這樣我們就必須使用 sqlSession.commit()方法,相當於使用了 JDBC 中的 connection.commit()方法實現事務提交。
Mybatis 自動動提交事務
@Before//在測試方法執行之前執行
public void init()throws Exception {
//1.讀取配置文件
in = Resources.getResourceAsStream("SqlMapConfig.xml");
//2.創建構建者對象
SqlSessionFactoryBuilder builder = new SqlSessionFactoryBuilder();
//3.創建 SqlSession 工廠對象
factory = builder.build(in);
//4.創建 SqlSession 對象,傳入參數爲true,代表開啓自動提交
session = factory.openSession(true);
//5.創建 Dao 的代理對象
userDao = session.getMapper(IUserDao.class);
}
@After//在測試方法執行完成之後執行
public void destroy() throws Exception{
//7.釋放資源
session.close();
in.close();
}
此時事務就設置爲自動提交了,同樣可以實現CUD操作時記錄的保存。雖然這也是一種方式,但就編程而言,設置爲自動提交方式爲 false再根據情況決定是否進行提交,這種方式更常用。因爲我們可以根據業務情況來決定提交是否進行提交。