MyBatis爲了解決經過一些不肯定性的條件進行SQL語句的拼接操做的問題, 提供了動態SQL. 具體來講,就是提供了一些標籤 <if> <where> <trim> <set> <choose> <foreach> 等.寫出可擴展SQL語句html
MyBatis 採用功能強大的基於 OGNL 的表達式來簡化操做java
OGNL( Object Graph Navigation Language )對象圖導航語言,這是一種強大的表達式語言,經過它能夠很是方便的來操做對象屬性。 相似於EL表達式,例:mysql
訪問對象屬性: person.namegit
調用方法: person.getName()github
調用靜態屬性/方法: @java.lang.Math@PI sql
調用構造方法: new com.bean.Person(‘admin’).name數據庫
運算符: +,-*,/,%api
邏輯運算符: in,not in,>,>=,<,<=,==,!=緩存
注意:xml中特殊符號如」,>,<等這些都須要使用轉義字符安全
標籤
1) <if>:用於完成簡單的判斷.只有一個屬性 test 用於判斷條件是否成立
2) <where>:在SQL語句中添加WHERE關鍵字, 做用:去掉 where 後面第一個條件前面的 and / or 。
<select id="getBook" resultType="main.beans.Book"> SELECT id,title,author,price FROM books <where> <if test="id != null"> and id= #{id}</if> <if test="title != null"> and title = #{title}</if> </where> </select>
3) <trim> : 能夠在條件判斷完的SQL語句的先後 添加內容 或者去掉指定的內容. 去掉第一個或最後一個
prefix: 添加前綴 prefixOverrides: 去掉前綴
suffix: 添加後綴 suffixOverrides: 去掉後綴
<delete id="deleteBook"> DELETE FROM books <trim prefix="WHERE" suffixOverrides="and"> <if test="id != null">id = #{id} and</if> <if test="title != null">itle = #{title} and</if> </trim > </delete>
4) <set> :在修改的操做中, 去掉SQL語句中多出的逗號,即在sql語句中最後句可能多出的逗號
<update id="updateBook"> UPDATE books <set> <if test="title != null">title = #{title},</if> <if test="author != null">author = #{author},</if> </set> where id = #{id} </update>
5) <sql> 標籤是用於抽取可重用的sql片斷,將使用頻繁的SQL片斷抽取出來,不只僅只提取整條sql語句,字段也能夠提取
id:指定被提取的 sql 片斷惟一標識被引用
引用:在任何須要插入此 sql 片斷的語句中使用 <include refid="id標識"></include> 引入便可
<sql id="bookFields"> id,title,author,price,sales,stock,img_path </sql> <insert id="insertBook" useGeneratedKeys="true" keyProperty="id"> INSERT INTO books (<include refid="bookFields"></include>) VALUES(#{id},#{title},#{author},#{price},#{sales},#{stock},#{imgPath}) </insert>
6) <choose> <when> <otherwise> : 用於分支判斷,最終只會知足其中的一個分支. 相似於 switch case 語句.
<select id="selectBookPrice" resultType="main.beans.Book"> SELECT <include refid="bookFields"></include> FROM books <where> <choose> <when test="id != null">id = #{id}</when> <otherwise>price > #{price}</otherwise> </choose> </where> </select>
7) <foreach>: 主要用於循環迭代
collection: 要迭代的集合
item: 當前從集合中迭代出的元素賦值的變量
open: 開始字符
close:結束字符
separator: 指定元素與元素之間的分隔符
index:
迭代的是List集合: index表示當前元素的下標
迭代的Map集合: index表示當前元素的 key
注意:此操做屬於批量操做需在 properties 配置的 url 中添加 allowMultiQueries=true 開啓批處理
<select id="getBooks" resultType="main.beans.Book"> SELECT <include refid="bookFields"></include> FROM books where id in <foreach collection="ids" item="id" separator="," open="(" close=")" > #{id} </foreach> </select>
MyBatis 包含一個很是強大的查詢緩存特性,它能夠很是方便地配置和定製。緩存能夠極大的提高查詢效率
MyBatis系統中默認定義了兩級緩存:一級緩存、二級緩存
默認狀況下,只有一級緩存(SqlSession級別的緩存,也稱爲本地緩存)開啓。
二級緩存須要手動開啓和配置,他是基於namespace級別的緩存。爲了提升擴展性。MyBatis定義了緩存接口Cache,支持第三方緩存。
1) 一級緩存(local cache), 即本地緩存, 做用域默認爲sqlSession。每一個sqlSession對象都有本身的一級緩存,相互獨立不共享。當 Session flush 或 close 後, 該 Session 中的全部 Cache 將被清空。
2) 本地緩存不能被關閉, 但能夠調用 clearCache() 來清空本地緩存, 或者改變緩存的做用域.
3) 在mybatis3.1以後, 能夠配置本地緩存的做用域. 在 mybatis.xml 中配置
4) 一級緩存的工做機制,同一次會話期間只要查詢過的數據都會保存在當前SqlSession的一個Map中
key: hashCode+查詢的SqlId+編寫的sql查詢語句+參數
緩存機制:
基於相同sqlSession屢次查詢,每次查詢都會先從緩存中獲取數據,若是緩存中沒獲取到數據,則從數據庫中獲取數據,以後,將數據存放到一級緩存。
一級緩存的失效問題
1)不一樣的SqlSession對應不一樣的一級緩存
2)同一個SqlSession可是查詢條件不一樣
3)同一個SqlSession兩次查詢期間執行了任何一次增刪改操做
增刪改操做,會默認清空緩存。
4)同一個SqlSession兩次查詢期間手動清空了緩存
總結:當同一 SqlSession 屢次查詢同一語句時,且中間未有增刪改或手動刷新、關閉、清空 clearCache() 過緩存,便會直接從緩存中取數據。若開啓了二級緩存則會先從二級緩存讀取,若二級緩存裏沒有再去一級緩存讀取,若是隻想從一級緩存中讀取可在對應 <select> 配置屬性中設置 useCache="false" 來關閉當前二級緩存,注意增刪改不涉及緩存機制
默認關閉,使用須要知足三個條件才被開啓
二級緩存:namespace級別緩存(sqlSessionFacotry)級別的緩存,做用域更廣可是須要在 sqlSessionFacotry 內的 sqlSession 提交或關閉之後纔會生效。即纔會將 sqlSession 中的緩存存到二級緩存中。
二級緩存使用的步驟:
① 全局配置文件中開啓二級緩存<setting name="cacheEnabled" value="true"/>
② 在須要使用二級緩存的映射文件( <mapper> 配置文件)使用 cache 標籤配置緩存<cache />
③ 注意:POJO須要實現 Serializable 接口
<cache> 標籤屬性
① eviction=「LRU」:緩存回收策略:默認的是 LRU。
LRU – 最近最少使用的:移除最長時間不被使用的對象。
FIFO – 先進先出:按對象進入緩存的順序來移除它們。
SOFT – 軟引用:移除基於垃圾回收器狀態和軟引用規則的對象。
WEAK – 弱引用:更積極地移除基於垃圾收集器狀態和弱引用規則的對象。
② flushInterval:刷新間隔,單位毫秒
默認狀況是不設置,也就是沒有刷新間隔,緩存僅僅調用語句時刷新
③ size:引用數目,正整數
表明緩存最多能夠存儲多少個對象,太大容易致使內存溢出
④ readOnly:只讀,默認是 false。雖然設爲true能提升效率可是爲了安全,所以不需設置此項
⑤ type:引入緩存類庫(第三方緩存)
其餘相關屬性設置
1) 全局setting的 cacheEnable:
配置二級緩存的開關,一級緩存一直是打開的。
2) select標籤的 useCache 屬性:
配置這個 select 是否使用二級緩存。一級緩存一直是使用的
3) sql標籤的 flushCache 屬性:
增刪改默認 flushCache=true。sql執行之後,會同時清空一級和二級緩存。
查詢默認 flushCache=false。
4) sqlSession.clearCache():只是用來清除一級緩存。
二級緩存機制
基於相同sqlSessionFactory下,屢次查詢,優先去二級緩存中獲取數據,二級緩存獲取不到數據,去一級緩存中獲取數據,一級緩存中也獲取不到數據,直接去數據庫中查詢數據。
查詢後,將數據直接存放一級緩存,提交或關閉 sqlSession 時,纔將一級緩存中的數據,緩存到二級緩存中。
EhCache 是一個純Java的進程內緩存框架,具備快速、精幹等特色,是Hibernate中默認的CacheProvider
整合EhCache緩存的步驟:
① 導入ehcache包,以及整合包,日誌包
ehcache-core-2.6.8.jar、mybatis-ehcache-1.0.3.jar
slf4j-api-1.6.1.jar、slf4j-log4j12-1.6.2.jar
② 編寫 ehcache.xml 配置文件
③ 配置 cache 標籤
<cache type="org.mybatis.caches.ehcache.EhcacheCache"></cache>
第三方緩存的使用機制,同二級緩存同樣也須要 setting 的 cacheEnable 設置爲 true 而且實現序列化接口 Serializable
<?xml version="1.0" encoding="UTF-8"?> <ehcache xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../config/ehcache.xsd"> <!-- 磁盤保存路徑 --> <diskStore path="F:\code\mysql\ehcache" /> <defaultCache maxElementsInMemory="1000" maxElementsOnDisk="10000000" eternal="false" overflowToDisk="true" timeToIdleSeconds="120" timeToLiveSeconds="120" diskExpiryThreadIntervalSeconds="120" memoryStoreEvictionPolicy="LRU"> </defaultCache> </ehcache>
MyBatis Generator: 簡稱MBG,是一個專門爲MyBatis框架使用者定製的代碼生成器,能夠快速的根據表生成對應的映射文件,接口,以及bean類。支持基本的增刪改查,以及QBC風格的條件查詢。可是錶鏈接、存儲過程等這些複雜sql的定義須要咱們手工編寫
Mybatis使用逆向工程步驟
1.加入逆向工程相關的jar包.
mybatis-generator-core-1.3.2.jar
2.配置逆向工程的配置文件: mbg.xml ==> 生成的版本 、 javaBean、Mapper接口、映射文件的生成策略 、 分析的表 .
mbg.xml 文件直接放在項目工程根目錄下方便路徑配置
<?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> <!-- targetRuntime: 執行生成的逆向工程的版本 MyBatis3Simple: 生成基本的CRUD MyBatis3: 生成帶條件的CRUD --> <context id="DB2Tables" targetRuntime="MyBatis3"> <!-- 數據庫鏈接設置--> <jdbcConnection driverClass="com.mysql.jdbc.Driver" connectionURL="jdbc:mysql://localhost:3306/bookstore?allowMultiQueries=true" userId="root" password="12345"> </jdbcConnection> <!-- javaBean的生成策略 bean的存放路徑--> <javaModelGenerator targetPackage="main.beans" targetProject=".\src"> <property name="enableSubPackages" value="true"/> <property name="trimStrings" value="true"/> </javaModelGenerator> <!-- SQL映射文件的生成策略 mapper.xml文件路徑--> <sqlMapGenerator targetPackage="main.mapper" targetProject=".\conf"> <property name="enableSubPackages" value="true"/> </sqlMapGenerator> <!-- Mapper接口的生成策略 mapper接口路徑--> <javaClientGenerator type="XMLMAPPER" targetPackage="main.mapper" targetProject=".\src"> <property name="enableSubPackages" value="true"/> </javaClientGenerator> <!-- 逆向分析的表 表名對應的javaBean名--> <table tableName="books" domainObjectName="Book"></table> <table tableName="users" domainObjectName="User"></table> </context> </generatorConfiguration>
3.執行生成代碼.
@Test public void testMbg() throws Exception { List<String> warnings = new ArrayList<String>(); boolean overwrite = true; File configFile = new File("mbg.xml"); ConfigurationParser cp = new ConfigurationParser(warnings); Configuration config = cp.parseConfiguration(configFile); DefaultShellCallback callback = new DefaultShellCallback(overwrite); MyBatisGenerator myBatisGenerator = new MyBatisGenerator(config,callback, warnings); myBatisGenerator.generate(null); }
PageHelper 是MyBatis中很是方便的第三方分頁插件。內部提供了 PageHelper 和 PageInfo 兩個很是強大的類庫。
使用步驟
1) 導入相關包 pagehelper-5.0.0.jar 和 jsqlparser-0.9.5.jar
2) 在MyBatis全局配置文件中配置分頁插件,注意標籤位置不可亂序
<plugins> <plugin interceptor="com.github.pagehelper.PageInterceptor"></plugin> </plugins>
3) 使用:在查詢出集合以前開啓分頁查詢
Page<Book> page = PageHelper.startPage(3,2 ); List<Book> books = mapper.selectByExample(bookExample); //查詢出當前爲第3頁,每頁顯示2條的圖書信息,其還可獲得更多頁碼相關值 books.forEach((book -> System.out.println("book = " + book))); PageInfo<Book> info = new PageInfo<>(books,3); System.out.println("=============獲取詳細分頁相關的信息================="); System.out.println("當前頁: " + info.getPageNum()); System.out.println("總頁碼: " + info.getPages()); System.out.println("總條數: " + info.getTotal()); System.out.println("每頁顯示的條數: " + info.getPageSize()); System.out.println("是不是第一頁: " + info.isIsFirstPage()); System.out.println("是不是最後一頁: " + info.isIsLastPage()); System.out.println("是否有上一頁: " + info.isHasPreviousPage()); System.out.println("是否有下一頁: " + info.isHasNextPage()); System.out.println("============分頁邏輯==============="); int[] nums = info.getNavigatepageNums(); for (int num : nums) { System.out.println("num = " + num); }
Page對象
在查詢以前經過PageHelper.startPage(頁碼,條數)設置分頁信息,該方法返回Page對象
PageInfo對象
在查詢完數據後,使用PageInfo對象封裝查詢結果,能夠獲取更詳細的分頁信息以及能夠完成分頁邏輯