java框架之mybatis(一)
一、簡介
1、概念
mybatis 是一個半自動輕量級的一個 orm 框架
2、作用
將 java 與 sql 分離,解決了 jdbc 的硬編碼問題,方便 sql 的修改;
sql 由開發人員控制,更加方便 sql 的調優;
3、快速開始
(1)原始方法
建一個全域性配置檔案,裡面是資料來源等執行環境的資訊;
建立一個sql 的對映檔案,並將這個檔案註冊到全域性的配置中;
根據全域性的配置檔案獲得一個 sqlsessionfactory;
通過 factory 獲得 sqlsession(非執行緒安全),一個sqlsession 就是和資料庫的一次會話,用完需要關閉;
sqlsession通過 sql 的唯一識別符號呼叫方法執行;
注意資料庫的欄位名和bean的欄位名要相同才能順利對映;
(2)介面式程式設計
定義一個介面,介面中定義操作資料庫的方法;
將介面和sql的對映檔案繫結:xml的namespace是介面全限定名,sql的id是介面中的方法名;
在 java 程式中通過session獲得藉口的實現類(代理物件)物件;
通過物件呼叫方法執行相應的sql;
二、配置檔案
1、全域性配置檔案
(1)xml 中引入 dtd 約束
(2)properties標籤:url引入網路或者磁碟的資源;resource引入 classpath 下的資源;
(3)settings標籤:設定一些mybatis執行時的重要引數
(4)typeAliases標籤:就是給 java 類起別名用的
- 別名不分大小寫;
- 可以單獨起也可以批量起;
- 預設別名就是類名;
- 也可以使用註解來起別名(@alias);
- java 中的基本資料型別和一些常用的類已經取好了別名(基本型別就是前面加 _ ;引用型別就是原類名)
(5)typeHandlers標籤:
- 就是處理 java 型別和資料庫型別的轉換的;
- 常用的型別 mybatis 都給預設處理了,不用我們自己去做;
- 當然是支援自定義的了;
(6)plugins標籤:作用就是攔截四大物件,改變他們的預設行為
(7)environments標籤:
- 用來配置環境的,可以配置多個環境,在default屬性裡可以指定預設的環境;
- 每個環境都應包含:transactionManager 和 dataSource
(8)databaseIdProvider標籤:
- 為mybatis提供多資料庫廠商的支援;
- 廠商標識在資料庫的驅動裡;
- 標籤內通過property標籤指定資料庫的別名;
- 在相應的sql語句的標籤上用databaseId引入資料庫的別名;
- 注意:主配置檔案裡的標籤的書寫的順序是有要求的,databaseIdProvider應該寫在envir 和 mapper 之間;
(9)mappers標籤:
- 作用就是註冊 sql 對映;
裡面具體的 mapper 的屬性有三種寫法:
-
resource:classpath 路徑下;
-
url:網路資源或者磁碟資源;
-
class:指定對應的對映的介面(條件是必須同包同名);
批量的註冊直接用package 標籤(條件是必須同包同名);
<?xml version="1.0" encoding="UTF-8" ?> <!DOCTYPE configuration PUBLIC "-//mybatis.org//DTD Config 3.0//EN" "http://mybatis.org/dtd/mybatis-3-config.dtd"> <configuration> <properties resource="conf/dbconfig.properties"></properties> <!-- <settings> <setting name="" value="" /> </settings> <typeAliases> 單獨起別名 <typeAlias type="" alias="" /> 批量起別名 <package name="" /> </typeAliases> <typeHandlers> <typeHandler handler="" /> </typeHandlers> <plugins> <plugin interceptor=""></plugin> </plugins>--> <environments default="development"> <!-- <environment id="test"> <transactionManager type=""></transactionManager> <dataSource type=""></dataSource> </environment> --> <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> <databaseIdProvider type="DB_VENDOR"> <property name="Oracle" value="oracle" /> <property name="MySQL" value="mysql" /> </databaseIdProvider> <mappers> <mapper resource="conf/TuserMapper.xml" /> </mappers> </configuration>
2、sql對映檔案概述
(1)增刪改測試
- int、long 和 boolean 型別的返回值我們可以直接用;
- 增刪改後一定要 commit;
(2)資料插入獲得自增主鍵
mysql:支援自增主鍵
useGeneratedKeys和keyProperty 屬性配合使用即可獲取到自增主鍵的值
oracle:不支援自增主鍵,靠序列來完成
1).在要執行的sql前用 selectKey 標籤來實現
2).相關的三個屬性分別是 keyProperty、resultType 和 order;
3).有兩種寫法分別是 order 的屬性值為 before 和 after;通常使用 before
3、對映檔案的引數處理
(1)單個引數
單個引數可以在 #{}中隨意寫;
(2)多個引數
多個引數預設在其中寫 param1 和 param2 等;也可以用註解@param 指定名稱;多個引數本質是封裝在一個map中;
業務相關的資料直接封裝在 pojo 中;
關聯性不高且使用的頻率不高的話的可以放在一個map裡;在map 裡可以隨意指定鍵名;
同時多個引數如果使用的頻率很高的話還可以封裝為一個 TO 物件;
集合和陣列的特殊處理:引數可以寫 collection、list 和 array;
(3)引數處理原始碼分析
引數封裝成map 的過程:總結起來就是引數多的時候就封裝成 map 集合,有@param註解的引數的鍵值就是指定的值,否則就是預設的;
(4)關於 #{} 和 ${}兩種取值的方法:
#{}
是以預編譯的形式來取引數的值的,可以防注入;
而${}
是直接拼接的;
大多數的情況採用#{}
,但在原生的 jdbc 不支援佔位符的地方可以使用${}
,比如order by ${age}
;
#{}進行引數設定的時候可以指定一些規則,比如:#{email,jdbcType.null},mybatis自動將 null值對映為jdbc的other型別,這個型別oracle不支援會報錯;
4、對映檔案的select 元素
(1)resultType
- resultType 的作用就是指定結果集的封裝的規則;
- 結果集封裝為 list型別直接寫 list裡資料型別即可;
- 封裝為 map 單條記錄直接寫 map 的別名;多條記錄寫pojo 的型別(map的值是pojo),map的鍵值在相應的方法上面用註解@mapKey 來指定pojo 中的屬性;
(2)resultMap(關聯查詢 | 分步查詢 | 延遲載入 | 集合屬性封裝)
- 配置列名屬性名對映
- resultMap也是用來定義結果集的封裝規則的(表的列名和pojo 的屬性名的對應關係);
- resultMap標籤兩個屬性 type是pojo型別,id是唯一標識;表中的主鍵列用id 封裝,普通列用 result 封裝;
用resultMap實現關聯查詢(前提pojo包裝pojo):
- 第一種方法是直接寫 property 的時候用屬性點屬性的方式就可以了;
- 第二種方法是在 resultMap 裡用 association 標籤實現關聯查詢,兩個屬性 property 和 javatype;
association 標籤用法
-
可以用來實現關聯查詢;
-
用 association 實現分步查詢:select屬性指定 mapper方法,column 屬性指定傳入方法的引數;
-
關聯查詢時,如果想按需載入,就可以在全域性 settings 裡設定lazyloading 為true,實現get相應的pojo
的時候再發出sql向資料庫查詢;
collection 標籤用法
- 用 collection 標籤實現集合型別屬性的封裝,屬性 property為相應的集合型別的屬性名,而ofType 是集合的泛型的型別;
collection 實現分步查詢和延遲載入:
-
實際上還是 select 將兩個介面方法、兩個sql關聯,再用 column 屬性傳入引數;
-
多個引數的傳遞可以用map,就是這樣的形式:{key1=col1,key2=col2};
-
fetchType屬性可以設定延遲載入;
discriminator鑑別器根據列的值做出不同的處理:還是寫在 resultMap裡,內含case標籤指定各種值的處理方法(封裝方法),其中指定封裝資料的型別時,type 和 map 必須二選一;這個東西用的少;
<?xml version="1.0" encoding="UTF-8" ?> <!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd"> <mapper namespace="com.wc.mapper.TuserMapper"> <!-- <resultMap type="tuser" id="map1"> <id property="uid" column="tid"/> <result property="uname" column="uname"/> <result property="age" column="age"/> 關聯查詢 <association property="dept" javaType="department"> <id property="did" column="did"/> <result property="dname" column="dname"/> </association> </resultMap> --> <resultMap type="tuser" id="map2"> <id property="uid" column="tid"/> <result property="uname" column="uname"/> <result property="age" column="age"/> <result property="did" column="did"/> <!-- select step by step --> <association property="dept" select="com.wc.mapper.DepartmentMapper.getDeptById" column="did"> <id property="did" column="did"/> <result property="dname" column="dname"/> </association> </resultMap> <select id="getById" resultMap="map2"> select * from tuser where tid = #{id} </select> </mapper>
三、動態sql
1、if 判斷
(1)OGNL(物件圖導航語言)
有點類似於 jsp 中的 el 表示式,可以用來取引數的值並作一些基本的運算;
(2)if 判斷
if 判斷拼接 where 條件存在的問題:就是可能會出現where後面直接是一個 and的情況
-
1)第一種方法:就是where 後面緊跟一個 1=1;
-
2)第二種方法:使用where 標籤,使用時注意條件的後就不要寫 and 了;
-
3)第三種方法:使用trim 標籤,可以通過屬性設定字首字尾和前後綴的覆蓋問題,where 前後多出的 and(or)都能解決;
set 標籤用來封裝修改條件,作用就是去除 set 的時候多餘的逗號,當然用 trim 標籤也可以實現,與if結合使用可以實現動態更新;
2、choose 分支選擇
(1)語法:choose----when----when----otherwise-----choose
(2)理解:類似於 java 中帶break 的 switch語句,只匹配一個條件;
3、foreach 遍歷
(1)遍歷集合拼接 where 條件(如:in 集合)
幾個常用的屬性 collection、item、separator、open、close、index(map的時候就是map的key);
(2)實現資料的批量插入
- mysql 第一種:在 values 後面用 foreach 遍歷拼接 sql;
- mysql 第二種:直接整個插入語句來迴圈,需要在資料庫的 url 後面傳參開啟多條語句執行的支援;
- oracle 第一種:用 plsql ,在begin 和 end 中來遍歷;
- oracle 第二種:迴圈用 select 語句將集合中的值從偽表中查出,再用查出的結果進行插入;
4、其他
*(1)內建引數:
- 除了我們傳入的引數,還有內建的引數,這裡的內建引數可以取到也可以判斷
- _parameter:封裝所有的引數,傳入的引數一個就是這個引數本身,傳入多個引數就是一個 map;
- databaseId:全域性配置檔案裡面配置了 databaseproviderid這裡可以取到;
- _parameter 和 if結合可以用來進行 where條件的拼接;
- databaseId 和 if 結合使用可以用來在一個 select 元素裡寫兩個資料庫的 sql;
(2)bind 標籤:作用就是將傳入的引數賦值給一個變數方便以後的呼叫,連個屬性name 和 value;
(3)sql 片段:
-
用 sql 標籤抽取可以重用的sql 片段方便以後在其他的sql 裡用include標籤用id引用,如查詢欄位的重用;
-
include 支援自定義 property ,在sql標籤的內部就能用${}取來使用;
四、快取
1、介紹
(1)作用:就是提升查詢的效率;
(2)分類:
- 一緩(本地快取):session 級別的快取,預設開啟,session關閉則失效;
- 二緩(全域性快取):namespace級別的快取,要手動開啟;
2、一級快取
(1)一級快取失效的四種情況
- sqlsession 不同,不同的session 之間不能共享資料;
- 引數不同的情況;
- 兩次相同的查詢之間有 增刪改 的操作;
- 第二次查詢之前手動清空快取;
3、二級快取
(1)作用:可以實現不同的 session 之間的資料共享,一個 namespace(一個介面)對應一個map(二級快取);
(2)原理:
- 一次會話中查詢的資料會預設儲存在一級快取中;
- 當對應的會話關閉的時候,如果開啟了二級快取,在session關閉清空快取資料之前會將資料存到二級快取中;
- 需要注意的是如果 session 沒有關閉,一級快取的資料是不會自動存到二級快取中的;
(3)使用:總開關(主配檔案裡的 setting)和分開關(sql對映檔案裡用 cache標籤來開啟)都要開啟;
4、快取原理和設定
快取相關設定
全域性的 cacheEnabled 和 select 標籤的 useCache 都是和二級快取相關的設定,不會影響一級快取;
flashCache屬性在增刪改的標籤裡是預設開啟,在 select 標籤裡是預設關閉的,這個屬性為 true的話會清空一二級的快取;
session 的 clearcache 方法只會清除當前 session 的一級快取;
全域性 LocalcacheScope 可以用來關閉一級快取(一般不用);
5、第三方快取整合(ehcache)
(1)步驟:
- 匯入快取的包和整合包;
- 引入ehcache配置檔案;
- 直接在mapper xml 中用 cache 標籤引用;
- 另一個 mapper 可以用 cache-ref 標籤來引用其他 mapper 的快取策略;