一概述 1.什麼是Mybatis? ⑴Mybatis是Apache的一個開源項目,原名為ibatis,移植到google code後改名為Mybatis,目前遷移到了Github。 ⑵Mybatis是一個支持定製化SQL、存儲過程以及高級映射的優秀持久層框架,避免了幾乎所有的JDBC代碼、手動設置參 ...
一概述
1.什麼是Mybatis?
⑴Mybatis是Apache的一個開源項目,原名為ibatis,移植到google code後改名為Mybatis,目前遷移到了Github。
⑵Mybatis是一個支持定製化SQL、存儲過程以及高級映射的優秀持久層框架,避免了幾乎所有的JDBC代碼、手動設置參數以及獲取結果集的過程。
2.Mybatis與Hibernate對比
兩者的主要區別在於封裝程度:
⑴Hibernate封裝程度較高,表現為可以自動建立映射關係,即查詢結果自動封裝為實體類對象,而Mybatis必須手動為結果指明映射的實體類。
⑵Hibernate封裝了SQL語句,而Mybatis中的SQL語句需要程式員編寫。
⑶Hibernate能夠創建表,Mybatis不能創建與修改表,只能修改表中的數據。
⑷正因為Hibernate封裝程度較高,獲得同樣的結果所需代碼比Mybatis複雜,執行速度慢,Web應用中速度是至關重要的,所以Hibernate正逐漸被Mybatis取代。
3.Mybatis體繫結構,由上至下:
⑴API介面:
Mybatis的頂層,Mybatis提供給開發人員的用於操作資料庫的入口,主要是一些對象中的方法。
⑵數據處理層:
頂層的API介面被調用以後,觸發數據處理層,該層具體負責SQL查找、SQL解析、SQL執行、結果映射。
⑶基礎支撐層:
為整個框架的運行提供了基礎性質的支撐,主要有配置載入、連接管理、事務管理、緩存管理。
4.Mybatis基本執行過程:
啟動時載入配置文件,為映射文件中的每一個SQL語句創建一個MappedStatement對象,通過API介面調用SQL語句,系統根據id找到對應的MappedStatement對象,解析成SQL語句,連接資料庫執行,最後將查詢結果映射成屬性或者對象。
5.配置文件:
<configuration> <!--載入包含資料庫連接四要素的屬性文件 --> <properties resource="dbConnection.properties"/> <!--為映射文件中的類起一個別名,這樣在映射文件中可以省去書寫全限定性類名,直接使用別名 --> <typeAliases> <typeAlias type="com.mybatis.beans.demo01.Student" alias="Student"/> <!--<package name="com.mybatis.beans.demo01" /> --> </typeAliases> <!--配置環境,可以有多個環境,比如測試環境,發佈環境,default選擇使用的環境。環境指的是資料庫管理方面的信息,比如數據源、事務--> <environments default="development"> <environment id="development"> <!--表示採用JDBC預設的事務管理器,項目開發時用DataSourceTransactionManger--> <transactionManager type="JDBC" /> <!--採用Mybatis自帶的資料庫連接池,項目開始時通常使用C3P0或者DBCP --> <dataSource type="POOLED"> <!--從載入的屬性文件中讀取資料庫連接四要素 --> <property name="driver" value="${jdbc.driver}" /> <property name="url" value="${jdbc.url}" /> <property name="username" value="${jdbc.username}" /> <property name="password" value="${jdbc.password}" /> </dataSource> </environment> </environments> <!--載入映射文件 --> <mappers> <mapper resource="com/mybatis/beans/demo01/Student.xml" /> </mappers> </configuration>
配置文件主要包含:
⑴資料庫連接四要素通常放在屬性文件中,便於更改。為每一個環境都創建一個屬性文件,key相同,當需要載入某個環境時,只需要將總環境的預設值設為該環境的id。從屬性文件中讀取數據的基本語法格式:${key}。
⑵<typeAliases>用於為類指定一個別名:
①<typeAlias type="com.mybatis.beans.demo01.Student" alias="Student"/>:為全限定性類名指定一個別名,在映射文件中使用該別名替代全限定性類名,使代碼簡潔。
②<package name="com.mybatis.beans.demo01" />:指定包名,在沒有註解的情況下,系統採用非限定性類名作為別名,首字母可以小寫。
⑶<environments>:配置文件中可以有多個環境,分別用於不同的用途,default屬性指定當前使用的環境。
⑷<environment>:主要包含事務管理器、數據源等。
⑸<mappers>:將映射文件載入到配置文件中。
6.映射文件:
<mapper namespace="student"> <insert id="insertStudent"> insert into tb_student(name,score)values(#{name},#{score}) ----------在數據插入完成後獲取插入數據的id------------ <selectKey resultType="int"keyProperty="id"> select@@identity </selectKey> </insert> <delete id="deleteStudent">delete from tb_student whereid=#{?}</delete> ------------------------------模糊查詢------------------------------- <select id=""resultType="xxxx">select name from xxx where name like '%'#{}'%'</select> <mapper>
⑴映射文件用於設定欄位與屬性的映射關係。
⑵namespace:命名空間,即名稱存在的範圍,用於區分不同映射文件中同名的SQL。
⑶id:在同一個映射文件中不可重覆,用於在程式中調用該SQL。
⑷parameterType:當參數類型是實體類時,可以直接使用配置文件中的別名。
⑸select:有返回值,返回值可以是屬性,也可以是實體類對象,因此必須指定單行數據返回值類型resultType,以便系統按照該類型返回查詢結果。
⑹Mybatis為常見的java類型設定了別名,別名大小寫不敏感,即大小寫作用相同。基本數據類型的別名在前面加下劃線,如_int,其他常用類型的別名就是首字元小寫後的非限定性類名,如String的別名是string,由於大小寫不敏感,也可以寫成String。
⑺語法介紹:
①#{屬性名}:獲取對象屬性值;
②#{xxx}:用作占位符,可以是任意合法字元,用於參數不是實體類對象時取得參數的值。
⑻模糊查詢語法格式:‘%’#{xxx},為了避免系統將占位符視作普通字元處理,占位符放在單引號或者雙引號外面,與單引號或者雙引號之間不使用任何連接。
7.預設封裝時,採用反射機制,封裝時根據欄位名調用set方法初始化對象,因此表中的欄位名必須與實體類中對應的屬性名相同,如果欄位名與屬性名不同,那麼該屬性無法被初始化。
屬性名與欄位名不一致時的解決方案:
①使用別名:通過別名將查詢結果的欄位名修改為屬性名,缺點是每一次查詢時都需要創建別名。
②使用resultMap:採用Hibernate的處理方式,手動在欄位與屬性之間建立映射:
<resultMap type="studentResultMap"id="studentMap"> <id column="id" property="sid" /> <result column="name" property="sname" /> </resultMap>
8.SqlSessionFactory
⑴相當於Hibernate中的SessionFactory對象,主要負責創建SqlSession對象。創建初始化過程耗費大量系統資源,並且線程安全,因此將對象設定為應用級的,即在整個應用範圍採用單例模式。
⑵創建:
InputStream input=Resources.getResourceAsStream("文件的類路徑");//基於路徑創建輸入流 SqlSessionFactory factory=new SqlSessionFactoryBuilder().build(input);
輸入流工廠對象創建完畢後自動關閉,不需要手動關閉。
9.SqlSession
⑴Mybatis持久化操作的核心,線程不安全,應該設置為多例的,即一個線程一個。
⑵創建:
SqlSession sqlSession=factory.openSession();//使用openSession的無參形式時,自動關閉自動提交
⑶主要方法:
①sqlSession.close():關閉sqlSession對象,如果未回滾,回滾。
⑷dirty:一個框架底層的boolean值,主要用於判斷當前緩存中內容與資料庫中內容是否相同,相同為false,不同為true,數據提交或者回滾時需要判斷該值。
10.使用log4j技術輸出日誌信息。
二 Mapper動態代理
1.如果Dao介面的方法名與映射文件中SQL語句的id相同,那麼根據方法名就可以找到對應的SQL語句,從而省去將方法與SQL語句綁定的過程。需要做兩點:方法名與id相同,命名空間為Dao介面的全限定性類名。
2.怎麼在java代碼中獲取操作對象?
由於採用Mapper動態代理,省去了Dao實現層,只剩下Dao介面,而Dao介面無法實例化,那麼就根據該介面創建一個代理對象,作為操作對象:
IDao dao=sqlSession.getMapper(IDao.class);
3.基本原理
利用JDK動態代理創建了一個代理對象,該代理對象在Dao方法與映射文件SQL語句間建立了映射關係,所以稱作
MapperProxy。
三多條件查詢
1.什麼是多條件查詢?
根據多個條件進行查詢,叫做多條件查詢,就是查詢時傳入多個參數,稱作多參數查詢更準確。
2.多參數查詢問題產生的原因?
同時向SQL語句傳入多個參數,就出現了一個對應問題,傳入的參數與SQL語句中的哪個占位符對應,因此產生了多參數查詢問題。Mybatis中進行持久化操作的方法只允許存在一個傳入SQL語句的參數。
3.解決方法
⑴手動封裝:為每一個參數設定一個key值,將多個key/value保存到Map對象中,將Map對象作為參數傳入SQL語句,在SQL語句中通過 #{key}獲取參數value的值。
⑵自動封裝:方法定義時設定key。
Student selectStudentByIndex(@Param("name")String name,@Param("score") double score);
⑶高版本多參數查詢不支持索引。
四 #在映射文件中的用法
1.#{attr}:當參數是實體類對象時,獲取屬性值;
2.#{?}:當參數是基本數據類型或者字元串時,用作占位符,獲取參數的值,{}內部可以是任意合法字元,一般用屬性名。
3.#{key}:當參數是Map集合時,通過key值獲取value的值。
五動態SQL
1.什麼是動態SQL?
根據傳入的參數選擇性執行SQL語句,這一過程叫做動態SQL.
2.動態SQL中用到的字元:
<if>\<where>\<choose when otherwise>\<foreach>。
3.<where if>:
從多個過濾條件中選擇若幹個。
⑴基本格式:
<where> <if test="scoreKey>0">score>#{scoreKey}</if> <if test="nameKey!=null &nameKey!=''">and name like"%"#{nameKey}"%"</if> </where>
⑵test用來指明判斷條件,其中使用key值;為了完成組合,除第一個<if>標簽外,其他標簽的內容都必須以連接符開頭,如and,or。
⑶映射文件是一個XML文檔,而在XML文檔中不允許使用> >= < <= &,必須使用對應的實體替換。
4.<where choose when otherwise>:
從多個條件中選擇第一個為真的執行。
基本格式:
<where> <choose> <when test="nameKey!=null and nameKey!=''"> name like"%"#{nameKey}"%"</when> <when test="scoreKey > 0">score>#{scoreKey}</when> <otherwise>1=2</otherwise> </choose> </where>
5.<where foreach>:遍歷列表。
⑴基本格式:
<select id="selectStudentsByArray"resultType="student"> select id,name,score from tb_student <where> <if test="array.length>0"> id in <foreach collection="array"item="myid" open="(" close=")"separator=","> #{myid} </foreach> </if> </where> </select>
⑴當參數類型是數組時,collection值為array;參數類型是List時,collection值為list。
⑵item表示遍歷的子對象,集合或者數組中一個元素。
⑶open/close/separator:用於拼湊JDBC中的(a,b,c)的列表形式。
六實體關聯查詢
1.什麼是實體關聯查詢?
兩個實體間存在關聯關係,即引用關係,通過一個實體查詢關聯的實體,這就是實體關聯查詢。
2.關聯關係查詢時必須手動地為欄位建立與屬性的映射關係。
3.一對多關聯查詢:
映射文件的編寫:
<resultMap id="countryMapAlone"type="Country"> <id property="cid" column="cid" /> <result property="cname" column="cname" /> <collection property="ministers" ofType="Minister"select="ministerSelect"column="cid" /> </resultMap> <select id="selectCountryByIdAlone" resultMap="countryMapAlone"> selectc id,cname from tb_country where cid=#{cid} </select> <select id="ministerSelect" resultType="Minister"> select mid,mname,countryId from tb_minister where countryId=#{cid} </select>
在<collection>標簽中:
⑴ofType:指明集合中的每一個元素的類型。
⑵select屬性用來指明從載入方的查詢語句。
⑶column屬性指明將主載入方查詢結果的哪個欄位傳入從載入方的查詢語句中。
4.多對一關聯查詢:
映射文件編寫:
<select id="selectMinisterById"resultMap="ministerMap"> select mid,mname,countryId from tb_minister where mid=#{id} </select> <resultMap id="ministerMap"type="com.mybatis.entityRelation.m2o.Minister"> <id property="mid" column="mid" /> <result property="mname" column="mname" /> <result property="countryId" column="countryId" /> <association property="country"javaType="com.mybatis.entityRelation.m2o.Country" select="selectCountry"column="countryId" /> </resultMap> <select id="selectCountry" resultType="com.mybatis.entityRelation.m2o.Country"> selectc id,cname from tb_country where cid=#{countryId} </select>
5.自關聯:
⑴什麼是自關聯?
兩個實體類除了一個關聯屬性外其他屬性完全相同,將兩個實體當做一個實體處理,這樣關聯關係就轉化為了自關聯。
⑵把自關聯看做一對多雙向關聯。
⑶查找自身及其子對象:
<select id="selectNewsLabelsById"resultMap=""> select id,name,pid from tb_newslabel where id=#{id} </select> <resultMap id="" type="newsLabel"> <id property="id" column="id" /> <result property="name" column="name" /> <result property="pid" column="pid" /> <collection property="childNewsLabels" ofType="newsLabel"select="selectChild"column="id" /> </resultMap> <select id="selectChild" resultType="newsLabel"> select id,name,pid from tb_newslabel where pid=#{id} </select>
6.多對多關聯查詢:
⑴將多對多關聯看做兩個一對多關聯,一方是原有兩方中的任一方,多方是中間表,中間表有兩個外鍵,分別引用其他兩張表的主鍵。
⑵多對多關聯查詢多採用表連接查詢,同時查詢三張表,因為這種操作方式簡單。
⑶多表聯合查詢分別查詢:
<select id="selectStudentByIdAlone" resultMap="aloneMap"> select sid,sname from tb_studentc where sid=#{sid} </select> <resultMap id="aloneMap"type="com.mybatis.entityRelation.m2m.Student"> <id property="sid" column="sid" /> <result property="sname" column="sname" /> <collection property="courses" ofType="com.mybatis.entityRelation.m2m.Course" select="selectCourse"column="sid" /> </resultMap> <select id="selectCourse"resultType="com.mybatis.entityRelation.m2m.Course"> select cid,cname from tb_course where cid in (select course_id from tb_mid where student_id=#{sid})//採用臨時表 </select>
七延時載入
1.什麼是延時載入?
載入主載入方時,不立即載入從載入方,而是根據設定延遲載入從載入方。
2.延時載入針對的關聯查詢時的從載入方,設定從載入方的載入時機。
3.Mybatis中載入從載入方的幾種方式:
⑴直接載入:主載入方載入完畢後,立即載入從載入方,未開啟延時載入時採用該載入方式。
⑵侵入式延遲:將從載入方當做主載入方的詳情,訪問主載入方的詳情時,載入從載入方。
⑶深度延遲:只有在訪問從載入方對象時才載入從載入方。
4.延時載入的設置:
⑴預設情況下,延遲載入是關閉的,主載入方載入完畢後立即載入從載入方。在配置文件中開啟延時載入:
<settings> <setting name="lazyLoadingEnabled" value="true" /> </settings>
⑵開啟延遲載入以後,預設採用深度延遲。
⑶如需要採用侵入式延遲:
<settings> <setting name="lazyLoadingEnabled" value="true" /> <setting name="aggressiveLazyLoading" value="true" /> </settings>
八緩存
1.緩存是記憶體中的臨時存儲區,用來存放從資料庫中載入的數據,目的是為了提高查詢速度。
2.緩存內容的來源:SQL查詢從資料庫中載入的數據。
3.緩存內容的類型:封裝的實體類對象與分散的屬性值。
4.Mybatis中用兩種緩存:一級緩存,二級緩存。
5.無論一級緩存,還是二級緩存,只在同一namespace中可見,對其他namespace的查詢不可見。
6.緩存的存儲格式:緩存以Map集合的形式存儲內容,key是SQL id與SQL語句的組合,value是從資料庫中載入的內容。
7.無論一級緩存,還是二級緩存,緩存查找依據都是SQLid與SQL語句,即根據SQL id與SQL語句查找緩存中是否具有相同的內容。
8.一級緩存與二級緩存持有的是同一對象的記憶體地址,執行增刪改操作,將會清空一級緩存,即銷毀引用地址指向的對象,同時預設清空二級緩存。清空的是緩存Map集合的value值,保留key值。
9.一級緩存:
⑴一級緩存:SqlSession級的,緩存中的內容只能在同一個SqlSession內部共用,生命周期與SqlSession相同。
⑵一級緩存是預設的緩存,無法關閉,也無法通過設置改變屬性,即只能採用預設的方式,不能自定義。
⑶sqlSession關閉意味著Session對象銷毀,一級緩存釋放持有的引用地址,而不是銷毀對象。
10.Mybatis提供了兩種二級緩存方案:內置二級緩存與第三方二級緩存Ehcache。
⑴二級緩存預設情況下是開啟的。
⑵二級緩存不會主動載入對象,要想將對象載入到二級緩存中,必須在命名空間下開啟二級緩存:<cache/>,該命名空間下所有查詢操作的結果都會被保存到二級緩存中。
⑶二級緩存的關閉:
①應用範圍關閉:<setting name="cacheEnabled" value="true" />;
②命名空間範圍關閉:註銷掉命名空間下的<cache/>.
③SQL範圍關閉:<select useCache="false"/>
⑷二級緩存使用原則:
①避免多個namespace操作同一張表:二級緩存是基於namespace的,不同namespace對二級緩存的操作是隔離的,相當於每一方都把資料庫中的數據讀取到記憶體中,各自獨立操縱,這樣當一方的操作同步到資料庫以後,另一方還在操作資料庫中改變了的數據,造成幻讀。
②不要在關聯關係表上執行增刪改操作:不同的表對應不同的namespace,同一張表可能同時被多個namespace操作,導致幻讀。
③查詢多於增刪改時使用二級緩存:增刪改清空緩存,消耗系統資源。
⑸開啟內置二級緩存:
①序列化實體類:應用內置二級緩存的實體類必須序列化。
②<cache/>:在指定命名空間使用二級緩存。
⑹使用Ehcache第三方緩存Ecache:
①導入架包;
②<cache type="org.mybatis.caches.ehcache.EhcacheCache" />:在命名空間指定使用Ehcache二級緩存;
③導入Ehcache配置文件ehcache.xml,放在類路徑下。
⑺預設情況下,執行增刪改操作會清空二級緩存,如果不希望某個增刪改操作清空二級緩存,可以在映射文件<insert/delete/update>標簽下設置,將flushCache設為false。由於一級緩存與二級緩存引用的是同一對象,如果不希望清空二級緩存,不能在一級緩存持有引用地址的情況下執行增刪改操作。
九註解
1.註解是在java類文件中添加註解以替代映射文件的註冊方式。
2.為了充分發揮框架的功能,Mybatis推薦使用映射文件,不建議使用註解。
3.常用註解:
⑴@Insert()/@Delete()/Update()。
⑵@Select(value=""):使用註解查詢時可以省略結果類型。
⑶@SelectKey(statement = "select@@identity",resultType=Integer.class,keyProperty = "id", before =false):獲取剛插入數據的主鍵值,必須與插入註解聯合使用。
⑷在配置文件中註冊Dao介面:
①<mapper class=""/>:通過Dao類註冊。
②<package name="Dao類所在的包"/>:通過包名註冊,可以同時註解該包下的多個Dao介面。