mybatis中連接池與事務

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再根據情況決定是否進行提交,這種方式更常用。因爲我們可以根據業務情況來決定提交是否進行提交。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章