JAVAORM框架之Mybatis (Ibatis) 詳解
目錄
- Mybatis基礎概念
- Mybatis開放方式演進
- Mybatis框架核心要點
- 關聯查詢
- 延遲加載(懶加載)
- 動態SQL
- Mybatis緩存
- Mybatis逆向工程
- PageHelper分頁插件
- 註解開發
Mybatis基礎概念
Mybatis是一個持久層框架
它對JDBC操作數據庫進行封裝,讓我們更關註SQL本身,而不需要花費精力去處理例如註冊驅動、創建connection、創建statement、手動設置參數、結果集檢索等jdbc繁雜的過程代碼。下面是Mybatis的架構圖
Mybatis又是如何解決JDBC中存在的問題呢?
1、 創建數據庫連接相關操作,存在硬編碼
? a) 解決方案:通過Mybatis全局配置文件,對數據庫連接進行配置
2、 statement相關操作,存在硬編碼
? a) 解決方案:通過Mapper映射文件,對statement相關處理進行配置。
?
3、 頻繁開啟數據庫連接,會降低數據庫處理性能。
? a) 解決方案:通過Mybatis全局配置文件,配置連接池。
?
?
Mybatis開放方式演進
Mybatis框架核心要點
關聯查詢
所謂的關聯查詢就是一對一和一對多以及多對多的應用,例如下面的例子
一對一 : 例如在獲取訂單的時候需要獲取該訂單所屬的用戶信息
解決思路 : 使用ResultMap或者ResultType自定義一個POJO進行結果映射一對多 : 例如在獲取用戶信息的時候需要獲取該用戶的所有訂單信息
延遲加載(懶加載)
關於延遲加載
- MyBatis中的延遲加載,也稱為懶加載,是指在進行關聯查詢時,按照設置延遲規則推遲對關聯對象的select查詢。延遲加載可以有效的減少數據庫壓力。
- Mybatis的延遲加載,需要通過resultMap標簽中的association和collection子標簽才能演示成功。
- Mybatis的延遲加載,也被稱為是嵌套查詢,對應的還有嵌套結果的概念,可以參考一對多關聯的案例。
- 註意:MyBatis的延遲加載只是對關聯對象的查詢有延遲設置,對於主加載對象都是直接執行查詢語句的。
延遲加載分類
MyBatis根據對關聯對象查詢的select語句的執行時機,分為三種類型:直接加載、侵入式加載與深度延遲加載
- 直接加載: 執行完對主加載對象的select語句,馬上執行對關聯對象的select查詢。
- 侵入式延遲:執行對主加載對象的查詢時,不會執行對關聯對象的查詢。但當要訪問主加載對象的詳情時,就會馬上執行關聯對象的select查詢。即對關聯對象的查詢執行,侵入到了主加載對象的詳情訪問中。也可以這樣理解:將關聯對象的詳情侵入到了主加載對象的詳情中,即將關聯對象的詳情作為主加載對象的詳情的一部分出現了。
- 深度延遲:執行對主加載對象的查詢時,不會執行對關聯對象的查詢。訪問主加載對象的詳情時也不會執行關聯對象的select查詢。只有當真正訪問關聯對象的詳情時,才會執行對關聯對象的select查詢。
延遲加載策略需要在Mybatis的全局配置文件中,通過
如何使用
直接加載 通過對全局參數:lazyLoadingEnabled進行設置,默認就是false。
<settings>
<!-- 延遲加載總開關 -->
<setting name="lazyLoadingEnabled" value="false"/>
</settings>
侵入式加載
<settings>
<!-- 延遲加載總開關 -->
<setting name="lazyLoadingEnabled" value="true"/>
<!-- 侵入式延遲加載開關 -->
<setting name="aggressiveLazyLoading" value="true"/>
</settings>
深度延遲加載
<settings>
<!-- 延遲加載總開關 -->
<setting name="lazyLoadingEnabled" value="true"/>
<!-- 侵入式延遲加載開關 -->
<setting name="aggressiveLazyLoading" value="false"/>
</settings>
動態SQL
動態SQL的思想:就是使用不同的動態SQL標簽去完成SQL字符串的拼接處理。
解決的問題 :
- 在映射文件中,會編寫很多有重疊部分的SQL語句,比如SELECT語句和WHERE語句等這些重疊語句,該如何處理
- 如果頁面傳遞過來一個參數,但是SQL語句中的條件有多個,此時會發生問題。
?
主要標簽
if標簽 where標簽 sql片段 foreach標簽
Mybatis緩存
- Mybatis提供查詢緩存,如果緩存中有數據就不用從數據庫中獲取,用於減輕數據壓力,提高系統性能。
- Mybatis的查詢緩存總共有兩級,我們稱之為一級緩存和二級緩存,如圖:
? 一級緩存是SqlSession級別的緩存。在操作數據庫時需要構造 sqlSession對象,在對象中有一個數據結構(HashMap)用於存儲緩存數據。不同的sqlSession之間的緩存數據區域(HashMap)是互相不影響的。
? 二級緩存是Mapper(namespace)級別的緩存。多個SqlSession去操作同一個Mapper的sql語句,多個SqlSession可以共用二級緩存,二級緩存是跨SqlSession的。
一級緩存原理圖
第一次發起查詢用戶id為1的用戶信息,先去找緩存中是否有id為1的用戶信息,如果沒有,從數據庫查詢用戶信息,將查詢到的用戶信息存儲到一級緩存中。
如果中間sqlSession去執行commit操作(執行插入、更新、刪除),清空SqlSession中的一級緩存,這樣做的目的為了讓緩存中存儲的是最新的信息,避免臟讀。
第二次發起查詢用戶id為1的用戶信息,先去找緩存中是否有id為1的用戶信息,緩存中有,直接從緩存中獲取用戶信息。
二級緩存原理圖
1. 第一次調用mapper下的SQL去查詢用戶信息。查詢到的信息會存到該mapper對應的二級緩存區域內。
2. 第二次調用相同namespace下的mapper映射文件中相同的SQL去查詢用戶信息。會去對應的二級緩存內取結果。
3. 如果調用相同namespace下的mapper映射文件中的增刪改SQL,並執行了commit操作。此時會清空該namespace下的二級緩存。
如何開啟二級緩存(默認關閉)
- 在核心配置文件SqlMapConfig.xml中加入以下內容(開啟二級緩存總開關):
<!-- 開啟二級緩存總開關 -->
<settings>
<setting name="cacheEnabled" value="true"/>
</settings>
- 在UserMapper映射文件中,加入以下內容,開啟二級緩存:
<!-- 開啟本mapper下的namespace的二級緩存,默認使用的是mybatis提供的PerpetualCache -->
<cache></cache>
說明 : 由於二級緩存的數據不一定都是存儲到內存中,它的存儲介質多種多樣,比如說存儲到文件系統中,所以需要給緩存的對象執行序列化。如果該類存在父類,那麽父類也要實現序列化。(既查詢結果對象要實現序列化接口)
Mybatis逆向工程
由於Mybatis是半自動化的ORM框架,所以仍然有很多事情需要我們去做
例如 : 編寫與數據庫表對應的實體,編寫Mapper接口,編寫Mapper配置文件
所謂的Mybatis逆向工程僅僅是一個項目所以只需要在下面配置中填寫好自己數據庫的相關信息,運行main方法既可以為我們生成POJO類,Mapper接口,Mapper配置文件
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE generatorConfiguration
PUBLIC "-//mybatis.org//DTD MyBatis Generator Configuration 1.0//EN"
"http://mybatis.org/dtd/mybatis-generator-config_1_0.dtd">
<generatorConfiguration>
<context id="testTables" targetRuntime="MyBatis3">
<commentGenerator>
<!-- 是否去除自動生成的註釋 true:是 : false:否 -->
<property name="suppressAllComments" value="true" />
</commentGenerator>
<!--數據庫連接的信息:驅動類、連接地址、用戶名、密碼 -->
<jdbcConnection driverClass="com.mysql.jdbc.Driver"
connectionURL="jdbc:mysql://localhost:3306/mybatis" userId="root" password="root">
</jdbcConnection>
<!-- <jdbcConnection driverClass="oracle.jdbc.OracleDriver" connectionURL="jdbc:oracle:thin:@127.0.0.1:1521:yycg"
userId="yycg" password="yycg"> </jdbcConnection> -->
<!-- 默認false,把JDBC DECIMAL 和 NUMERIC 類型解析為 Integer,為 true時把JDBC DECIMAL
和 NUMERIC 類型解析為java.math.BigDecimal -->
<javaTypeResolver>
<property name="forceBigDecimals" value="false" />
</javaTypeResolver>
<!-- targetProject:生成PO類的位置 -->
<javaModelGenerator targetPackage="com.kkb.ms.po"
targetProject=".\src">
<!-- enableSubPackages:是否讓schema作為包的後綴 -->
<property name="enableSubPackages" value="false" />
<!-- 從數據庫返回的值被清理前後的空格 -->
<property name="trimStrings" value="true" />
</javaModelGenerator>
<!-- targetProject:mapper映射文件生成的位置 -->
<sqlMapGenerator targetPackage="com.kkb.ms.mapper"
targetProject=".\src">
<!-- enableSubPackages:是否讓schema作為包的後綴 -->
<property name="enableSubPackages" value="false" />
</sqlMapGenerator>
<!-- targetPackage:mapper接口生成的位置 -->
<javaClientGenerator type="XMLMAPPER"
targetPackage="com.kkb.ms.mapper" targetProject=".\src">
<!-- enableSubPackages:是否讓schema作為包的後綴 -->
<property name="enableSubPackages" value="false" />
</javaClientGenerator>
<!-- 指定數據庫表 -->
<table schema="" tableName="user"></table>
<table schema="" tableName="order"></table>
</context>
</generatorConfiguration>
註意 :每次執行逆向工程代碼之前,先刪除原來已經生成的mapper xml文件再進行生成。mapper.xml文件的內容不是被覆蓋而是進行內容追加,會導致mybatis解析失敗。po類及mapper.java文件的內容是直接覆蓋沒有此問題。
PageHelper分頁插件
如果你也在用Mybatis,建議嘗試該分頁插件,這個一定是最方便使用的分頁插件。
使用方法如下
首先增加依賴
<dependency>
<groupId>com.github.pagehelper</groupId>
<artifactId>pagehelper</artifactId>
<version>5.1.6</version>
</dependency>
配置PageHelper
? Mybatis全局配置文件
<plugins>
<plugin interceptor="com.github.pagehelper.PageInterceptor">
<!-- config params as the following -->
<property name="helperDialect" value="mysql"/>
</plugin>
</plugins>
? Spring配置文件
<bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
<!-- other configuration -->
<property name="plugins">
<array>
<bean class="com.github.pagehelper.PageInterceptor">
<property name="properties">
<!-- config params as the following -->
<value>
helperDialect=mysql
</value>
</property>
</bean>
</array>
</property>
</bean>
在項目中使用PageHelper
//獲取第1頁,10條內容,默認查詢總數count
PageHelper.startPage(1, 10);
List<Country> list = countryMapper.selectAll();
//用PageInfo對結果進行包裝
PageInfo page = new PageInfo(list);
//測試PageInfo全部屬性
//PageInfo包含了非常全面的分頁屬性
assertEquals(1, page.getPageNum());
assertEquals(10, page.getPageSize());
註意事項
1. 需要分頁的查詢語句,必須是處於PageHelper.startPage(1, 10);後面的第一條語句。
2. 如果查詢語句是使用resultMap進行的嵌套結果映射,則無法使用PageHelper進行分頁。
?
Mybatis插件介紹
參考地址:https://www.cnblogs.com/fangjian0423/p/mybatis-interceptor.html
StatementHandler
ParameterHandler
ResultSetHandler
註解開發
使用註解開發,我們不再需要XML配置文件
常用註解說明
增刪改查-靜態SQL
- @Insert:相當於
標簽,實現新增 - @Update: 相當於
標簽,實現更新 - @Delete: 相當於
標簽,實現刪除 - @Select: 相當於
- @SelectKey:相當於
標簽,實現主鍵返回
增刪改查-動態SQL
- @InsertProvider: 相當於
標簽,實現新增 - @UpdateProvider: 相當於
標簽,實現更新 - @DeleteProvider: 相當於
標簽,實現刪除 - @SelectProvider: 相當於
多表關聯
? @Results: 相當於<resultMap>標簽,需要和@Result註解一起使用。
? @Result: 相當於<result>和<id>標簽,實現結果集中某一列的數據映射
* column 數據庫的列名
* property 需要裝配的屬性名
* one 需要使用的@One 註解(@Result(one=@One()))
* many 需要使用的@Many 註解(@Result(many=@many()))
? @One: 相當於<association>標簽,實現一對一關系映射
? @Many:相當於<collection>標簽,實現一對多關系映射
? @One和@Many註解的屬性:
* select 屬性:代表將要執行的 sql 語句
* fetchType 屬性:代表加載方式,一般如果要延遲加載都設置為 LAZY 的值
? 使用格式:
1. @Results({@Result(),@Result()})或@Results(@Result())
2. @Result(column=" ",property="",one=@One(select=""))
輔助註解
- @Options:相當於標簽屬性的設置
- @Param:如果你的映射器的方法需要多個參數,這個註解可以被應用於映射器的方法參數來給每個參數一個名字。
其他註解
- @CacheNamespace:相當於
標簽,實現二級緩存。
屬性:implemetation,eviction,flushInterval,size,readWrite,blocking和properties
JAVAORM框架之Mybatis (Ibatis) 詳解