1. 程式人生 > >SSM in Action——MyBatis事務管理和快取機制

SSM in Action——MyBatis事務管理和快取機制

MyBatis的事務管理

眾所周知,事務的四個特性ACID。永續性、原子性、隔離性以及一致性。

Transaction介面 mybatis的事務設計重點就是Transaction介面,它有兩個實現類,分別是JdbcTransaction和ManagedTransaction。同時MyBatis還設計了TransactionFactory介面,和工廠類的實現類JdbcTransactionFactory以及ManagedTransactionFactory來獲取事務的例項物件。

對事務而言,應該具有如下幾個動作:

  • create
  • commit
  • rollback
  • close

MyBatis將事務抽象成Transaction介面,該介面原始碼如下: 在這裡插入圖片描述

  • 通過JDBC的事務管理機制是通過java.sql.Connection物件完成對事務的提交回滾和關閉等操作。
  • 通過Managed的事務管理機制,MyBatis本身不會去實現事務管理,而是委託容器如WebLogic、JBoss等來實現對事務的管理。

事務的配置建立和使用 我們在使用MyBatis的時候,會在mybatis-config.xml中,使用如下的資訊:

<environment id="mysql">
            <!--指定事務管理型別,type="JDBC"指直接簡單的使用JDBC的提交和回滾設定-->
            <transactionManager
type="JDBC"/>
<!--dataSource指資料來源配置,POOLED是JDBC連線物件的資料來源連線池的實現--> <dataSource type="POOLED"> <property name="driver" value="com.mysql.jdbc.Driver"/> <property name="url" value="jdbc:mysql://localhost:3306/mybatis?useSSL=false"
/>
<property name="username" value="root"/> <property name="password" value="woshixiao"/> </dataSource> </environment>

<transactionManager>就告訴我們使用哪種型別的事務管理機制。

MyBatis事務的建立是交給工廠來完成的,如果我們將<transactionManager>的type配置為JDBC,那麼,在myBatis初始化解析<environment>節點的時候,會根據type='JDBC’來建立一個JdbcTransactionFactory工廠。 其原始碼如下: 在這裡插入圖片描述 這是一個很典型的工廠模式。 我們看看怎麼得到的Transaction物件例項的。拿JDBC舉例: 在這裡插入圖片描述 我們再來看看Transaction是怎麼工作的,同樣拿jdbc舉例 :(這裡只展示commit和rollback) 在這裡插入圖片描述 哇,居然這麼賴皮,這不就是使用了connection的兩個函式麼,是的JdbcTransaction就是使用java.sql.Connection上的commit和rollback等函式來工作的,正如前面所說。

那麼你可能會疑問,Managed是如何讓容器來管理事務Transaction的整個生命週期的呢? 意思是ManagedTransaction的commit和rollback功能,不會對事務有任何影響,它什麼都不會做,它只是將事務管理的權力移交給了容器來實現。 在這裡插入圖片描述

MyBatis的快取機制

一級快取(SqlSession級別) MyBatiss的一級快取是SqlSession級別的快取,在操作資料庫時需要構造SqlSession物件,在物件中有一個HashMap用於儲存快取資料。不同的SqlSession之間的快取是互不影響的。 當 同一個 SqlSession執行兩次相同的sql語句時,第一次執行完畢將會寫入快取,第二次就不再去資料庫查詢了。需要注意的是,如果SqlSession執行了DML操作(insert、update和delete),那麼MyBatis會清空SqlSession中的快取避免出現髒讀和不可重複讀等情況。 以下是兩次重複的sql select語句: 在這裡插入圖片描述 以下是兩次重複的sql select語句,但是中間插入了delete語句: 在這裡插入圖片描述 結果顯而易見吧,第一次只在資料庫裡查詢了一次,第二次由於執行了刪除操作,所以在資料庫裡查詢了兩次。(當然前提是sqlsession沒有關閉,是同一個sqlsession)

二級快取(mapper級別) 二級快取是mapper級別的快取,使用二級快取的時候,多個SqlSession使用同一個Mapper的sql語句去操作資料庫,得到的資料庫會存在二級快取區域。它同樣是HashMap進行資料儲存。 二級快取是共享的,其作用域是mapper的同一個Namespace。 不同的SqlSession兩次執行相同的namespace下的sql語句,且傳遞的引數也相同,那麼第一次執行完畢會寫入快取,第二次查詢會從快取中獲取資料。 但是MyBatis預設不開啟二級快取,需要在setting全域性引數中配置開啟二級快取。<setting name="cacheEnabled" value="true"/> 在Mapper.xml建立LRU快取:

<cache eviction="LRU" flushInterval="60000"
	size="512" readOnly="true"/>

cahce元素用來開啟mapper的namespace下的二級快取,該元素的屬性設定如下:

  • flushInterval:重新整理間隔。預設是沒有重新整理間隔,只有在呼叫語句時重新整理。
  • size:快取數目。預設1024。
  • readOnly:只讀。只讀的快取匯給所有呼叫者返回快取物件的相同例項。因此這些物件不能被修改。這提供了很重要的效能優勢。可讀寫的快取會返回快取物件的拷貝(通過序列化),這雖然會慢一些,但是安全。因此預設是false。
  • eviction:收回策略。也可以理解為替換策略: 包括LRU FIFO SOFT WEAK。

我們之前兩次select查詢中間插入delete,通過這個方法,可以不用再去資料庫查詢。

為什麼避免使用二級快取 在符合【Cache使用時的注意事項】的要求時,並沒有什麼危害。 其他情況就會有很多危害了。 針對一個表的某些操作不在他獨立的namespace下進行。 例如在UserMapper.xml中有大多數針對user表的操作。但是在一個XXXMapper.xml中,還有針對user單表的操作。 這會導致user在兩個名稱空間下的資料不一致。如果在UserMapper.xml中做了重新整理快取的操作,在XXXMapper.xml中快取仍然有效,如果有針對user的單表查詢,使用快取的結果可能會不正確。 更危險的情況是在XXXMapper.xml做了insert,update,delete操作時,會導致UserMapper.xml中的各種操作充滿未知和風險。