MyBatis SQL參數傳遞(掌握)java
SQL映射器Mapper接口(掌握)Mybmysql
atis批量操做(理解掌握)程序員
(多對一)關聯映射(掌握)面試
(一對多,多對多)集合映射 算法
MyBatis原理回顧(Object Relational Mapping,簡稱ORM)spring
ORM的缺點是會犧牲程序的執行效率和會固定思惟模式。
從系統結構上來看,採用ORM的系統通常都是多層系統,系統的層次多了,效率就會下降。ORM是一種徹底的面向對象的作法,而面向對象的作法也會對性能產生必定的影響。
在咱們開發系統時,通常都有性能問題。性能問題主要產生在算法不正確和與數據庫不正確的使用上。ORM所生成的代碼通常不太可能寫出很高效的算法,在數據庫應用上更有可能會被誤用,主要體如今對持久對象的提取和和數據的加工處理上,若是用上了ORM,程序員頗有可能將所有的數據提取到內存對象中,而後再進行過濾和加工處理,這樣就容易產生性能問題。
在對對象作持久化時,ORM通常會持久化全部的屬性,有時,這是不但願的。
但ORM是一種工具,工具確實能解決一些重複,簡單的勞動。這是不能否認的。但咱們不能期望工具能一勞永逸的解決全部問題,有些問題仍是須要特殊處理的,但須要特殊處理的部分對絕大多數的系統,應該是不多的。sql
S(spring)S(springmvc)M(mybatis)集成(掌握)數據庫
MyBatis是一個ORM持久化框架,應用到系統持久層(Dao);緩存
一個MyBatis的應用程序都以一個SqlSessionFactory對象(單例)的實例爲核心安全
SqlSession對象徹底包含以數據庫爲背景的全部執行SQL操做的方法
MyBatis是針對數據庫交互的一個輔助框架,也是對jdbc作了的簡單封裝,以xml配置代替Java代碼來管理數據庫的交互細節!!
MyBatis可使用簡單的XML或註解用於配置和原始映射,將接口(Mapper)和Java的POJO(Plain Old Java Objects,普通的Java對象)映射成數據庫中一條記錄。
MyBatis是一個支持普通SQL查詢,存儲過程和高級映射的優秀持久層框架。MyBatis消除了幾乎全部的JDBC代碼和參數的手工設置以及對結果集的檢索封裝。
加入mybatis
- MyBatis SQL參數傳遞
#{OGNL表達式} 和 ${OGNL表達式} 的區別
1.1. #{OGNL表達式}
MyBatis會把這個表達式使用?(佔位符)替換,做爲一個sql參數使用:推薦使用
好比name的值爲:
定義SQL: select * from t_user where name = #{name}
最終SQL: select * from t_user where name = ?
1.2. ${OGNL表達式}
MyBatis會把這個表達式的值替換到sql中,做爲sql的組成部分;
該方式主要用於程序拼接SQL;
若是sql中使用${OGNL},而且參數的類型是(integer,string....)那麼OGNL表達式能夠寫成任意東西;
1.3. ${OGNL}表達式的應用場景:
1.3.1. 不能用在登陸,會出現sql注入
好比登陸功能,在輸入name的時候能夠人爲的制形成功:
User user=new User();
user.setName("\"admin\" or \"1=1\" ");
user.setPassword("\"admin\" ");
定義SQL: select id,name,password from t_user where name = ${name} and password=${password}
最終SQL: select id,name,password from t_user where name="test" or "1=1" and password="test" 出現sql注入
能夠用在order by + limit的場景
#{}和${}的使用
resultMap和ParameterMap書寫拼寫要使用#{},resultType 和parameterType類型使用${},使用例子以下:
Select ID,COMMAND from Message where COMMAND=#{command}
Select ID,COMMAND from Message where COMMAND=‘${command}’
前者解析爲:
Select ID,COMMAND from Message where COMMAND=?具備預編譯效果
後者解析爲:
Select ID,COMMAND from Message where COMMAND=段子 不具備預編譯效果
可是,例如當頁面向後臺傳遞一個列名(屬性名)的時候,是不但願被預編譯出一個?的,此時要用到$格式;
如:加上 order by${param} ,此時param是一個列名。
#{}和 ognl表達式
通常參數的拼寫仍是保證統一風格爲好,便於人讀。
常常碰到這樣的面試題目:#{}和${}的區別是什麼?
網上的答案是:#{}是預編譯處理,$ {}是字符串替換。mybatis在處理#{}時,會將sql中的#{}替換爲?號,調用PreparedStatement的set方法來賦值;mybatis在處理 $ { } 時,就是把 ${ } 替換成變量的值。使用 #{} 能夠有效的防止SQL注入,提升系統安全性。
對於這個題目我感受要抓住兩點:
(1)$ 符號通常用來看成佔位符,常使用Linux腳本的人應該對此有更深的體會吧。既然是佔位符,固然就是被用來替換的。知道了這點就能很容易區分$和#,從而不容易記錯了。
(2)預編譯的機制。預編譯是提早對SQL語句進行預編譯,而其後注入的參數將不會再進行SQL編譯。咱們知道,SQL注入是發生在編譯的過程當中,由於惡意注入了某些特殊字符,最後被編譯成了惡意的執行操做。而預編譯機制則能夠很好的防止SQL注入。
最後想說的是,對於mybatis 以及 sql 而言,每個考點背後都是有一個深入的思想存在的,應該好好的體會。這樣才能真正的作到技術提高,成爲技術大牛。
這第三個例子雖說的是#{}和{}通用的問題,也就是說在此種狀況下#{}和
{}是通用的,只不過須要些小的轉換.如例子中須要手動
拼接單引號 ' ' 到變量值的先後,確保sql語句正常.
簡單說#{}是通過預編譯的,是安全的,而${}是未通過預編譯的,僅僅是取變量的值,是非安全的,存在sql注入.
這裏先說一下只能的情況,從我們前面的例子中也能看出,ord
{}了,用#{}會多個' '致使sql語句失效.此外還有一個like 語句後也須要用${},簡單想一下
就能明白.因爲僅僅是簡單的取值,所以以前sq
{},那麼不作任何處理的時候是存在sql注入危險的.你說怎麼防止,那我只
能悲慘的告訴你,你得手動處理過濾一下輸入的內容,如判斷一下輸入的參數的長度是否正常(注入語句通常很長),更精確寫查詢一下輸入的參數
- SQL映射器Mapper接口
MyBatis基於代理機制,可讓咱們無需再編寫Dao的實現。直接把之前的dao接口定義成符合規則的Mapper。
Mybatis的批量操做(foreach)
1 <!-- delete from product where id in ( ? , ? ) 批量刪除: 2 collection="list":傳入的list,至關於map的key,經過list獲得傳入的整個集合的值; 3 index="index" :每次循環的索引 4 item="id" :每次循環的這個值 5 open="(" :以什麼開始 6 separator=",":分隔符 7 close=")":以什麼結束 8 --> 9 <delete id="deleteBatch" parameterType="java.util.List"> 10 delete from product where id 11 in 12 <foreach collection="list" index="index" item="id" open="(" 13 separator="," close=")"> 14 #{id} 15 </foreach> 16 </delete>
1 <!-- 批量插入: 2 insert into product(productName,salePrice,costPrice,cutoff,supplier,brand,dir_id) 3 values (?,?,?,?,?,?,?) , (?,?,?,?,?,?,?) 4 parameterType:傳入參數是:java.util.List的類型的; 5 對傳入的list進行foreach循環:取出值填入插入的values中: 6 collection="list":這個不能修改,表示傳入的一個list相似於一個key是list,獲得傳入的list集合 7 index="index":每一次遍歷的序號 8 item="item":每次遍歷的這個對象別名,能夠修改 9 separator=",":每遍歷一次後的分隔符 10 --> 11 <insert id="insertBatch" parameterType="java.util.List"> 12 insert into 13 product(productName,salePrice,costPrice,cutoff,supplier,brand,dir_id) 14 values 15 <foreach collection="list" index="index" item="item" 16 separator=","> 17 (#{item.productName},#{item.salePrice},#{item.costPrice},#{item.cutoff},#{item.supplier},#{item.brand},#{item.dir_id}) 18 </foreach> 19 </insert>
關聯映射(多對一)
多對一:
多個員工屬於一個部門,domain:在員工這方建立一個部門:在多方有一個外鍵
一對多:
一個部門有多個員工:Domain:在部門有一個員工list:在多方有一個外鍵
多對多:
角色和權限:一個角色擁有對個權限,一個權限屬於多個角色
Domain:使用list表示:使用中間表維護關係
parameterType ,入參的全限定類名或類型別名 keyColumn ,設置數據表自動生成的主鍵名。對特定數據庫(如PostgreSQL),若自動生成的主鍵不是第一個字段則必須設置 keyProperty ,默認值unset,用於設置getGeneratedKeys方法或selectKey子元素返回值將賦值到領域模型的哪一個屬性中 useGeneratedKeys ,取值範圍true|false(默認值),設置是否使用JDBC的getGenereatedKeys方法獲取主鍵並賦值到keyProperty設置的領域模型屬性中。MySQL和SQLServer執行auto-generated key field,所以當數據庫設置好自增加主鍵後,可經過JDBC的getGeneratedKeys方法獲取。但像Oralce等不支持auto-generated key field的數據庫就不能用這種方法獲取主鍵了 statementType ,取值範圍STATEMENT,PREPARED(默認值),CALLABLE flushCache ,取值範圍true(默認值)|false,設置執行該操做後是否會清空二級緩存和本地緩存 timeout ,默認爲unset(依賴jdbc驅動器的設置),設置執行該操做的最大時限,超時將拋異常 databaseId ,取值範圍oracle|mysql等,表示數據庫廠家,元素內部可經過`<if test="_databaseId = 'oracle'">`來爲特定數據庫指定不一樣的sql語句--------------------- 做者:零下