Mybatis入門

軟件開發中的框架

- 框架是 可被應用開發者定製的應用骨架html

- 框架是一種規則,保證開發者遵循相同的方式開發程序java

- 框架提倡"不要重複造輪子",對基礎功能進行封裝mysql

框架的優勢

- 極大提升了開發效率算法

- 統一的編碼規則,利於團隊管理sql

- 靈活配置的應用,擁有更好的維護性數據庫

SSM開發框架

MyBatis入門

1 什麼是MyBatis

- MyBatis是優秀的持久層框架:apache

  經過DAO類結合Mybatis框架讓咱們快速完成對數據的增刪改查,緩存

  持久就是將內存中的數據保存到數據庫中,防止重啓後數據丟失.安全

- MyBatis使用XML將SQL與程序解耦,便於維護session

- MyBatis學習簡單,執行高效.是JDBC的延申

官網:https://mybatis.org/mybatis-3/zh/index.html

2 MyBatis開發流程

1 2

3 pojo 4

5 6

MyBatis是經過SqlSession對象對數據進行操做的,SqlSession對象由SessionFactory的對象生成。

 3 MyBatis環境配置

 finish

中央倉庫在國外有時下載比較慢,爲了解決這個問題,能夠在pom.xml增長一個鏡像倉庫配置

 

 jdbc驅動(這裏是mysql)

 IDEA內置的數據庫客戶端

 

有時可能出現下載不成功的狀況

解決方法:

1.在Mysql官網找到對應版本的jar包: https://dev.mysql.com/downloads/connector/j/

 官網下載太慢時,能夠經過MvnJar(https://www.mvnjar.com/)搜索對應的jar包來下載

2.將下載好的jar包將jar包放在IDEA的配置目錄或Maven倉庫中(只要能找到就行)

在IDEA的Mysql驅動文件列表中添加下載好的jar包

 

一切就緒後,點擊測試鏈接,若是顯示success表示鏈接成功,再點擊ok就配置好了

建立一個全新的數據庫並導入初始化表 (用數據源的方式)

在文件夾上點擊鼠標右鍵

執行成功後

 

還能夠修改表結構

 

 resource目錄下要新建立一個xml文件

 

xml聲明

dtd聲明

注:

 &的轉義: &

能夠有多個數據源的環境配置

默認用哪一個用default設置,值爲數據源對應的id的值

environment只能夠配置一個數據庫,每一個配置好的environment能夠當作一個數據源,而environments標籤用於數據源的配置,能夠配置多個數據源。

 1 <?xml version="1.0" encoding="UTF-8"?>
 2 <!DOCTYPE configuration
 3         PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
 4         "http://mybatis.org/dtd/mybatis-3-config.dtd">
 5 <configuration>
 6     <settings>
 7         <!-- goods_id ==> goodsId 駝峯命名轉換 -->
 8         <setting name="mapUnderscoreToCamelCase" value="true"/>
 9     </settings>
10 
11     <!--設置默認指向的數據庫-->
12     <environments default="dev">
13         <!--配置環境,不一樣的環境不一樣的id名字-->
14         <environment id="dev">
15             <!-- 採用JDBC方式對數據庫事務進行commit/rollback -->
16             <transactionManager type="JDBC"></transactionManager>
17             <!--採用鏈接池方式管理數據庫鏈接-->
18             <dataSource type="POOLED">
19                 <property name="driver" value="com.mysql.jdbc.Driver"/>
20                 <property name="url" value="jdbc:mysql://localhost:3306/babytun?useUnicode=true&amp;characterEncoding=UTF-8"/>
21                 <property name="username" value="root"/>
22                 <property name="password" value="root"/>
23             </dataSource>
24         </environment>
25     </environments>
26     <mappers>
27         <!--<mapper class="com.imooc.mybatis.dao.GoodsDAO"/>-->
28         <package name="com.imooc.mybatis.dao"/>
29     </mappers>
30 </configuration>
View Code

4 SqlSessionFactory

SqlSessionFactory

SqlSession

添加單元測試框架,經過單元測試能夠了解程序的狀況

 該包中新建一個測試類

在方法上寫test註解

只有添加了test註解,junit才能對這個類執行

 文本文件

返回reader對象

build經過reader對象解析xml,返回對應的sqlsessionfactory對象

opensession:建立一個sqlsession對象

getConnection:得到底層的數據庫鏈接對象

5 初始化工具類MyBatisUtils

 如何保證SqlSessionFactory在應用中全局惟一

 1 package com.imooc.mybatis.utils;
 2 
 3 import org.apache.ibatis.io.Resources;
 4 import org.apache.ibatis.session.SqlSession;
 5 import org.apache.ibatis.session.SqlSessionFactory;
 6 import org.apache.ibatis.session.SqlSessionFactoryBuilder;
 7 
 8 import java.io.IOException;
 9 import java.io.Reader;
10 
11 /**
12  * MyBatisUtils工具類,建立全局惟一的SqlSessionFactory對象
13  */
14 public class MyBatisUtils {
15     //利用static(靜態)屬於類不屬於對象,且全局惟一
16     private static SqlSessionFactory sqlSessionFactory = null;
17     //利用靜態塊在初始化類時實例化sqlSessionFactory
18     static {
19         Reader reader = null;
20         try {
21             reader = Resources.getResourceAsReader("mybatis-config.xml");
22             sqlSessionFactory = new SqlSessionFactoryBuilder().build(reader);
23         } catch (IOException e) {
24             e.printStackTrace();
25             //初始化錯誤時,經過拋出異常ExceptionInInitializerError通知調用者
26             throw new ExceptionInInitializerError(e);
27         }
28     }
29 
30     /**
31      * openSession 建立一個新的SqlSession對象
32      * @return SqlSession對象
33      */
34     public static SqlSession openSession(){
35         //默認SqlSession對自動提交事務數據(commit)
36         //設置false表明關閉自動提交,改成手動提交事務數據
37         return sqlSessionFactory.openSession(false);
38     }
39 
40     /**
41      * 釋放一個有效的SqlSession對象
42      * @param session 準備釋放SqlSession對象
43      */
44     public static void closeSession(SqlSession session){
45         if(session != null){
46             session.close();
47         }
48     }
49 }
View Code

測試類中使用

6 MyBatis數據查詢步驟

1→2

3→4

5→6

1.建立實體類

增長一些列的自由屬性,與goods表一一對應,

寫好字段信息後,生成get,set方法

 1 package com.imooc.mybatis.entity;
 2 
 3 import java.util.List;
 4 
 5 public class Goods {
 6     private Integer goodsId;//商品編號
 7     private String title;//標題
 8     private String subTitle;//子標題
 9     private Float originalCost;//原始價格
10     private Float currentPrice;//當前價格
11     private Float discount;//折扣率
12     private Integer isFreeDelivery;//是否包郵 ,1-包郵 0-不包郵
13     private Integer categoryId;//分類編號
14     private List<GoodsDetail> goodsDetails;
15 
16     public Integer getGoodsId() {
17         return goodsId;
18     }
19 
20     public void setGoodsId(Integer goodsId) {
21         this.goodsId = goodsId;
22     }
23 
24     public String getTitle() {
25         return title;
26     }
27 
28     public void setTitle(String title) {
29         this.title = title;
30     }
31 
32     public String getSubTitle() {
33         return subTitle;
34     }
35 
36     public void setSubTitle(String subTitle) {
37         this.subTitle = subTitle;
38     }
39 
40     public Float getOriginalCost() {
41         return originalCost;
42     }
43 
44     public void setOriginalCost(Float originalCost) {
45         this.originalCost = originalCost;
46     }
47 
48     public Float getCurrentPrice() {
49         return currentPrice;
50     }
51 
52     public void setCurrentPrice(Float currentPrice) {
53         this.currentPrice = currentPrice;
54     }
55 
56     public Float getDiscount() {
57         return discount;
58     }
59 
60     public void setDiscount(Float discount) {
61         this.discount = discount;
62     }
63 
64     public Integer getIsFreeDelivery() {
65         return isFreeDelivery;
66     }
67 
68     public void setIsFreeDelivery(Integer isFreeDelivery) {
69         this.isFreeDelivery = isFreeDelivery;
70     }
71 
72     public Integer getCategoryId() {
73         return categoryId;
74     }
75 
76     public void setCategoryId(Integer categoryId) {
77         this.categoryId = categoryId;
78     }
79 
80     public List<GoodsDetail> getGoodsDetails() {
81         return goodsDetails;
82     }
83 
84     public void setGoodsDetails(List<GoodsDetail> goodsDetails) {
85         this.goodsDetails = goodsDetails;
86     }
87 }
View Code

2.建立mapper  xml

說明實體類和哪一個表對應

  1 <?xml version="1.0" encoding="UTF-8"?>
  2 <!DOCTYPE mapper
  3         PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
  4         "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
  5 <mapper namespace="goods">
  6     <!--開啓了二級緩存
  7         eviction是緩存的清除策略,當緩存對象數量達到上限後,自動觸發對應算法對緩存對象清除
  8             1.LRU – 最近最少使用的:移除最長時間不被使用的對象。
  9             O1 O2 O3 O4 .. O512
 10             14 99 83 1     893
 11             2.FIFO – 先進先出:按對象進入緩存的順序來移除它們。
 12             3.SOFT – 軟引用:移除基於垃圾回收器狀態和軟引用規則的對象。
 13             4.WEAK – 弱引用:更積極地移除基於垃圾收集器狀態和弱引用規則的對象。
 14 
 15         flushInterval 表明間隔多長時間自動清空緩存,單位毫秒,600000毫秒 = 10分鐘
 16         size 緩存存儲上限,用於保存對象或集合(1個集合算1個對象)的數量上限
 17         readOnly 設置爲true ,表明返回只讀緩存,每次從緩存取出的是緩存對象自己.這種執行效率較高
 18                  設置爲false , 表明每次取出的是緩存對象的"副本",每一次取出的對象都是不一樣的,這種安全性較高
 19     -->
 20     <cache eviction="LRU" flushInterval="600000" size="512" readOnly="true"/>
 21     <!-- useCache="false"表明不使用緩存 -->
 22     <select id="selectAll" resultType="com.imooc.mybatis.entity.Goods" useCache="false">
 23         select * from t_goods order by goods_id desc limit 10
 24     </select>
 25     <!-- 單參數傳遞,使用parameterType指定參數的數據類型便可,SQL中#{value}提取參數-->
 26     <select id="selectById" parameterType="Integer" resultType="com.imooc.mybatis.entity.Goods">
 27         select * from t_goods where goods_id = #{value}
 28     </select>
 29 
 30     <!-- 多參數傳遞時,使用parameterType指定Map接口,SQL中#{key}提取參數 -->
 31     <select id="selectByPriceRange" parameterType="java.util.Map" resultType="com.imooc.mybatis.entity.Goods">
 32         select * from t_goods
 33         where
 34           current_price between  #{min} and #{max}
 35         order by current_price
 36         limit 0,#{limt}
 37     </select>
 38 
 39     <!-- 利用LinkedHashMap保存多表關聯結果
 40         MyBatis會將每一條記錄包裝爲LinkedHashMap對象
 41         key是字段名  value是字段對應的值 , 字段類型根據表結構進行自動判斷
 42         優勢: 易於擴展,易於使用
 43         缺點: 太過靈活,沒法進行編譯時檢查
 44      -->
 45     <select id="selectGoodsMap" resultType="java.util.LinkedHashMap" flushCache="true">
 46         select g.* , c.category_name,'1' as test from t_goods g , t_category c
 47         where g.category_id = c.category_id
 48     </select>
 49 
 50     <!--結果映射-->
 51     <resultMap id="rmGoods" type="com.imooc.mybatis.dto.GoodsDTO">
 52         <!--設置主鍵字段與屬性映射-->
 53         <id property="goods.goodsId" column="goods_id"></id>
 54         <!--設置非主鍵字段與屬性映射-->
 55         <result property="goods.title" column="title"></result>
 56         <result property="goods.originalCost" column="original_cost"></result>
 57         <result property="goods.currentPrice" column="current_price"></result>
 58         <result property="goods.discount" column="discount"></result>
 59         <result property="goods.isFreeDelivery" column="is_free_delivery"></result>
 60         <result property="goods.categoryId" column="category_id"></result>
 61         <result property="category.categoryId" column="category_id"></result>
 62         <result property="category.categoryName" column="category_name"></result>
 63         <result property="category.parentId" column="parent_id"></result>
 64         <result property="category.categoryLevel" column="category_level"></result>
 65         <result property="category.categoryOrder" column="category_order"></result>
 66 
 67 
 68         <result property="test" column="test"/>
 69     </resultMap>
 70     <select id="selectGoodsDTO" resultMap="rmGoods">
 71         select g.* , c.*,'1' as test from t_goods g , t_category c
 72         where g.category_id = c.category_id
 73     </select>
 74     <!--flushCache="true"在sql執行後強制清空緩存-->
 75     <insert id="insert" parameterType="com.imooc.mybatis.entity.Goods" flushCache="true">
 76         INSERT INTO t_goods(title, sub_title, original_cost, current_price, discount, is_free_delivery, category_id)
 77         VALUES (#{title} , #{subTitle} , #{originalCost}, #{currentPrice}, #{discount}, #{isFreeDelivery}, #{categoryId})
 78       <!--<selectKey resultType="Integer" keyProperty="goodsId" order="AFTER">-->
 79           <!--select last_insert_id()-->
 80       <!--</selectKey>-->
 81     </insert>
 82 
 83     <update id="update" parameterType="com.imooc.mybatis.entity.Goods">
 84         UPDATE t_goods
 85         SET
 86           title = #{title} ,
 87           sub_title = #{subTitle} ,
 88           original_cost = #{originalCost} ,
 89           current_price = #{currentPrice} ,
 90           discount = #{discount} ,
 91           is_free_delivery = #{isFreeDelivery} ,
 92           category_id = #{categoryId}
 93         WHERE
 94           goods_id = #{goodsId}
 95     </update>
 96     <!--delete from t_goods where goods_id in (1920,1921)-->
 97     <delete id="delete" parameterType="Integer">
 98         delete from t_goods where goods_id = #{value}
 99     </delete>
100 
101     <select id="selectByTitle" parameterType="java.util.Map" resultType="com.imooc.mybatis.entity.Goods">
102         select * from t_goods where title = #{title}
103         ${order}
104     </select>
105 
106     <select id="dynamicSQL" parameterType="java.util.Map" resultType="com.imooc.mybatis.entity.Goods">
107         select * from t_goods
108         <where>
109           <if test="categoryId != null">
110               and category_id = #{categoryId}
111           </if>
112           <if test="currentPrice != null">
113               and current_price &lt; #{currentPrice}
114           </if>
115         </where>
116     </select>
117 
118     <!--
119         resultMap可用於說明一對多或者多對一的映射邏輯
120         id 是resultMap屬性引用的標誌
121         type 指向One的實體(Goods)
122     -->
123     <resultMap id="rmGoods1" type="com.imooc.mybatis.entity.Goods">
124         <!-- 映射goods對象的主鍵到goods_id字段 -->
125         <id column="goods_id" property="goodsId"></id>
126         <!--
127             collection的含義是,在
128             select * from t_goods limit 0,1 獲得結果後,對全部Goods對象遍歷獲得goods_id字段值,
129             並代入到goodsDetail命名空間的findByGoodsId的SQL中執行查詢,
130             將獲得的"商品詳情"集合賦值給goodsDetails List對象.
131         -->
132         <collection property="goodsDetails" select="goodsDetail.selectByGoodsId"
133                     column="goods_id"/>
134     </resultMap>
135     <select id="selectOneToMany" resultMap="rmGoods1">
136         select * from t_goods limit 0,10
137     </select>
138 
139     <select id="selectPage" resultType="com.imooc.mybatis.entity.Goods">
140         select * from t_goods where current_price &lt; 1000
141     </select>
142 
143     <!--INSERT INTO table-->
144     <!--VALUES ("a" , "a1" , "a2"),("b" , "b1" , "b2"),(....)-->
145     <insert id="batchInsert" parameterType="java.util.List">
146         INSERT INTO t_goods(title, sub_title, original_cost, current_price, discount, is_free_delivery, category_id)
147         VALUES
148         <foreach collection="list" item="item" index="index" separator=",">
149             (#{item.title},#{item.subTitle}, #{item.originalCost}, #{item.currentPrice}, #{item.discount}, #{item.isFreeDelivery}, #{item.categoryId})
150         </foreach>
151     </insert>
152     <!--in (1901,1902)-->
153     <delete id="batchDelete" parameterType="java.util.List">
154         DELETE FROM t_goods WHERE goods_id in
155         <foreach collection="list" item="item" index="index" open="(" close=")" separator=",">
156             #{item}
157         </foreach>
158     </delete>
159 </mapper>
View Code

注意dtd聲明與以前不一樣

 

namesapce:命名空間,相似java中的包,對於不一樣表或不一樣功能的sql語句能夠指定不一樣的命名空間,

      經過不一樣的命名空間就能夠區分開不一樣的sql語句了.不一樣命名空間中的sql id能夠同名

 id:sql的名字

ResultType:數據返回的對象,sql語句執行完後會自動的將獲得的每一條記錄包裝成對應的goods對象

如何讓mybatis認識這個goods.xml?

要在mybatis-config.xml中聲明

 下面用測試類執行寫好的sql

返回的是goods對象

對於表中有下劃線的字段 在實體類中因爲語法問題 只能用駝峯命名法,這樣會形成丟值的問題

只需在mybatis文件中增長駝峯命名法與字段名轉換的配置就可

 

SQL傳參

1)查詢

 

 ①根據id查一條數據

第二個參數傳入的值類型要與mapper中  parameterType的類型一致!

②根據價值範圍查詢

mybatis只支持一個parameterType的傳遞,若是要傳遞多個,parameterType中設置的就不能是某個基礎類型,而是Map

 1 <!-- 單參數傳遞,使用parameterType指定參數的數據類型便可,SQL中#{value}提取參數-->
 2     <select id="selectById" parameterType="Integer" resultType="com.imooc.mybatis.entity.Goods">
 3         select * from t_goods where goods_id = #{value}
 4     </select>
 5 
 6     <!-- 多參數傳遞時,使用parameterType指定Map接口,SQL中#{key}提取參數 -->
 7     <select id="selectByPriceRange" parameterType="java.util.Map" resultType="com.imooc.mybatis.entity.Goods">
 8         select * from t_goods
 9         where
10           current_price between  #{min} and #{max}
11         order by current_price
12         limit 0,#{limt}
13     </select>

若映射文件中,SQL語句對應的id是全局惟一的,調用時也能夠不寫命名空間

2)MyBatis獲取多表關聯查詢結果

 

有一個問題:返回的map中,對應的字段順序是混亂的

由於hashmap的機制決定,key是按照key的hash值來排序的,而哈希值是一個不穩定的數字

爲了保證字段的先後順序一致

返回值不要使用Map接口,而要使用具體的對象 

 

map還能夠本身進行擴展字段

 

 

7 ResultMap結果映射

擴展一個java對象 對多表查詢返回的結果進行保存

對goods對象進行擴展

如何讓mybatis自動對其進行對應賦值呢?

 

 測試類:

 resultMap中對應數據庫的字段的屬性應該是column

8 MyBatis日誌輸出

什麼是日誌?

9 MyBatis內置日誌工廠

 

step1 添加依賴

 

 

執行後,在控制檯能夠看到打印出來的sql語句

 

step 2 展示日誌 自定義日誌 

resource文件夾下新建logback.html文件

appender 輸出器

class 不能隨便寫 意思是向控制檯進行打印輸出 

pattern 輸出時間 + 線程名稱 + 日誌級別(-5:按五個字符右對齊) + 是哪一個類產生的日誌({36}:最多容許36字符,超過會採用簡寫形式)  +  具體的日誌輸出內容 + 換行

root 打印的跟標籤

level 日誌輸出級別

appender-ref的ref屬性 :debug級別以上的信息都會按照pattern中定義的格式在console中輸出,開發環境通常設置爲debug,生產環境,通常設置爲info.

 1 <?xml version="1.0" encoding="UTF-8"?>
 2 <configuration>
 3    <appender name="console" class="ch.qos.logback.core.ConsoleAppender">
 4        <encoder>
 5            <pattern>%d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n</pattern>
 6        </encoder>
 7    </appender>
 8 
 9     <!--
10         日誌輸出級別(優先級高到低):
11         error: 錯誤 - 系統的故障日誌
12         warn: 警告 - 存在風險或使用不當的日誌
13         info: 通常性消息
14         debug: 程序內部用於調試信息
15         trace: 程序運行的跟蹤信息
16      -->
17     <root level="debug">
18         <appender-ref ref="console"/>
19     </root>
20 </configuration>

logback官網:http://logback.qos.ch/     

  文檔(Documentation)中能夠看到各類logback的配置細節

logback中文網:http://www.logback.cn/

MyBatis配置SLFJ日誌組件 

10 數據庫事務

先往日誌中寫,經過commit提交後會一次性把全部日誌寫入數據表中

若是發現有數據丟失,客戶端能夠發起回滾功能,這時事務日誌中的全部日誌將會所有被刪除

11 MyBatis數據寫入 

MyBatis寫操做包含三種:

新增:

獲取最新插入的主鍵:selectKeyuseGeneratedKeys

 

 

oracle中要用序列sql實現

 

更新:

刪除:

12 Map的妙用

Map的適用場景

 - 爲SQL語句傳入多個參數

 - 查詢返結果包含跨表字段

13 ResultMap結果映射

14 MyBatis預防SQL注入攻擊

15 MyBatis工做流程

16 動態sql

應用場景:

根據選擇條件搜索

 

 

 爲了解決上述問題,使用where標籤,自動判斷and是否會產生語法錯誤

17  Mybatis二級緩存

一級緩存,每一個對象有一個,用完釋放就沒有了

相同命名空間的二級緩存中,一級緩存是能夠共享的

總結:

1.

不一樣對象,同一個session,相同的sql寫了兩次,只執行一次

相同的對象,不一樣的session,相同的sql分別寫了一次,這兩次都會執行

不一樣對象,同一個session,兩個相同的sql之間使用commit強制清空了緩存,就會執行兩次

2.在實際開發中,一級緩存會被默認開啓,但它的生命週期較短,緩存的開啓和關閉之間只執行了少許的sql語句.

這裏的緩存對象很快被釋放,這也意味着緩存使用率並不高.爲了解決這個問題,mybatis提供了二級緩存.

3.二級緩存須要手動開啓,咱們要在對應的xml文件中進行配置(如該例子中的goods.xml)

開啓了二級緩存後,在不一樣的session中查詢相同的數據,全局只執行了一次sql

運行結果:

 上下兩個sql的哈希值也是一致的,說明他們在同一塊內存中

一共執行了兩次sql,第一次沒有經過緩存,第二次經過緩存提取,因此命中率1/2 = 0.5

在實際開發中,緩存命中率越高代碼緩存的使用效率越高.對程序優化效果越好,二級緩存存儲到了命名空間這個級別上,不會由於session的開啓和關閉跟着銷燬.

4.二級緩存相關參數

 list返回結果不固定,緩存命中率不高,相似狀況,不推薦使用二級緩存,設置useCache爲false便可

通常將單一結果存入二級緩存中

內存足夠的狀況下.size不要過小.如1000個實體對象,size設置1000

size表示緩存存儲的對象或集合的數量的上限。若是是集合,不論裏面存儲多少個對象,都表明一個對象

有時須要在執行一個sql以後立馬清空緩存,而不是在commit後清空,只要將flushCache設置爲true便可,切該條sql結果不會放入緩存

18 Mybatis多表級聯查詢

 

應用:商品和詳情對象關聯查詢

19 分頁插件PageHelper

 

 

PageHelper使用流程

 

不一樣數據庫分頁的實現原理

1)Mysql

2)Oracle

3)SQL Server 2000

4)SQL Server 2012+

20 Mybatis批處理

 

21 Mybatis配置C3P0鏈接池

 

22 MyBatis註解開發

相關文章
相關標籤/搜索