- 框架是 可被應用開發者定製的應用骨架html
- 框架是一種規則,保證開發者遵循相同的方式開發程序java
- 框架提倡"不要重複造輪子",對基礎功能進行封裝mysql
- 極大提升了開發效率算法
- 統一的編碼規則,利於團隊管理sql
- 靈活配置的應用,擁有更好的維護性數據庫
- MyBatis是優秀的持久層框架:apache
經過DAO類結合Mybatis框架讓咱們快速完成對數據的增刪改查,緩存
持久就是將內存中的數據保存到數據庫中,防止重啓後數據丟失.安全
- MyBatis使用XML將SQL與程序解耦,便於維護session
- MyBatis學習簡單,執行高效.是JDBC的延申
官網:https://mybatis.org/mybatis-3/zh/index.html
1 2
3 pojo 4
5 6
MyBatis是經過SqlSession對象對數據進行操做的,SqlSession對象由SessionFactory的對象生成。
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&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>
SqlSessionFactory
SqlSession
添加單元測試框架,經過單元測試能夠了解程序的狀況
該包中新建一個測試類
在方法上寫test註解
只有添加了test註解,junit才能對這個類執行
文本文件
返回reader對象
build經過reader對象解析xml,返回對應的sqlsessionfactory對象
opensession:建立一個sqlsession對象
getConnection:得到底層的數據庫鏈接對象
如何保證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 }
測試類中使用
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 }
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 < #{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 < 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>
注意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還能夠本身進行擴展字段
擴展一個java對象 對多表查詢返回的結果進行保存
對goods對象進行擴展
如何讓mybatis自動對其進行對應賦值呢?
測試類:
resultMap中對應數據庫的字段的屬性應該是column
什麼是日誌?
執行後,在控制檯能夠看到打印出來的sql語句
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日誌組件
先往日誌中寫,經過commit提交後會一次性把全部日誌寫入數據表中
若是發現有數據丟失,客戶端能夠發起回滾功能,這時事務日誌中的全部日誌將會所有被刪除
MyBatis寫操做包含三種:
新增:
獲取最新插入的主鍵:selectKey和useGeneratedKeys
oracle中要用序列sql實現
更新:
刪除:
Map的適用場景
- 爲SQL語句傳入多個參數
- 查詢返結果包含跨表字段
應用場景:
根據選擇條件搜索
爲了解決上述問題,使用where標籤,自動判斷and是否會產生語法錯誤
一級緩存,每一個對象有一個,用完釋放就沒有了
相同命名空間的二級緩存中,一級緩存是能夠共享的
總結:
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結果不會放入緩存
應用:商品和詳情對象關聯查詢
1)Mysql
2)Oracle
3)SQL Server 2000
4)SQL Server 2012+