mybatis框架學習-連接池與事務管理


連接池

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 類來表示 UNPOOLEDPOOLED 類型的數據源。

在這三種數據源中,我們一般采用的是 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>


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM