Day2 Mybatis初識(二)
mapper接口開發
傳統dao的開發問題(ibatis)
方法調用:字符串易錯,硬編碼
mapper代理開發
a) 編寫全局配置
b) 編寫接口(自動根據接口和映射文件創建實現類)
c) 編寫映射文件
規範:
A. 映射文件和mapper接口同包同名(批量加載映射文件)
B. 接口的全限定名稱必須和mapper映射文件的namespace保持一致
C. 接口中方法名稱和mapper中的標簽id保持一致
D. 方法的參數類型和mapper的paramerType保持一致
E. 方法的返回值類型和mapper的resultType和resultMap保持一致
<mapper namespace="mapper.BookMapper"> <select id="queryAll" resultType="book"> select * from book </select> </mapper>
d) 測試
SqlSession session = MybatisUtils.getSession(); //根據mapper接口生成實現類對象 BookMapper mapper = session.getMapper(BookMapper.class); System.out.println(mapper.queryAll()); MybatisUtils.closeSession(); //junit:單元測試 //1.加入junit的jar //2.使用junit實現測試(@test:作為單元直接運行 @before/@after:在test之前運行 )
輸入參數和輸出結果
輸出結果
a) resultType:
如果結果集中所有的字段和對象中屬性名稱一一對應則映射成功;
如果結果集中字段的名稱和屬性名稱部分一致,則一致的部分映射成功。
如果結果集中字段的名稱和屬性名稱都不一致,則不會創建對象。
b) 字段和屬性不一致實現封裝
A. 起別名
B. resultMap(實現字段和屬性之間的映射)
<!-- 實現結果集和對象的映射 id:唯一標識 type:封裝的對象類型 --> <resultMap type="book" id="bookMap"> <!-- id:描述主鍵字段和屬性之間的映射關系 column:字段 property:屬性 --> <id column="bi" property="bid"/> <!-- result:非主鍵字段的映射 --> <result column="bnam" property="bname"/> <result column="autho" property="author"/> <result column="pric" property="price"/> </resultMap> <select id="queryAll" resultMap="bookMap"> select * from book </select>
動態sql
if: <select id="queryCombo" parameterType="book" resultType="book"> select * from book where 1 = 1 <if test="bid != 0"> and bid = #{bid} </if> <if test="bname != null"> and bname = #{bname} </if> </select> choose: <choose> <when test="bid != 0"> and bid = #{bid} </when> <otherwise> and bname = #{bname} </otherwise> </choose> where <where> <if test="bid != 0"> and bid = #{bid} </if> <if test="bname != null"> and bname = #{bname} </if> </where> foreach: select * from book where bid in <!-- collection:遍歷的集合 item:每一項值 open:開始 close:結束 separator:分隔符 --> <foreach collection="list" item="bid" open="(" close=")" separator=","> #{bid} </foreach>
高級結果映射
1) 查詢的結果集分布於多張表
2) 一對多:Role和User(查詢role級聯查詢所有的員工信息)
<resultMap type="role" id="RoleMap"> <id column="rid" property="rid"/> <result column="rname" property="rname"/> <!-- collection:將結果集數據封裝到集合中 property:屬性 ofType:單個對象的類型 column:關聯的鍵 --> <collection property="users" ofType="user" column="rid"> <id column="uid" property="uid"/> <result column="uname" property="uname"/> <result column="rid" property="rid"/> </collection> </resultMap> <select id="queryRoleAndUser" resultMap="RoleMap"> select * from role r left join `user` u on r.rid = u.rid </select> Rolemapper.xml <resultMap type="role" id="RoleMap2"> <id column="rid" property="rid"/> <result column="rname" property="rname"/> <!-- collection:將結果集數據封裝到集合中 property:屬性 ofType:單個對象的類型 column:關聯的鍵 --> <collection property="users" ofType="user" column="rid" select="mapper.UserMapper.selectUser"> </collection> </resultMap> <select id="queryRoleAndUser2" resultMap="RoleMap2"> select * from role </select> UserMapper.xml <select id="selectUser" resultType="user"> select * from user where rid = #{rid} </select>
3) 一對一:查詢user及其角色(user)
<resultMap type="user" id="userMap"> <id column="uid" property="uid"/> <result column="uname" property="uname"/> <!-- 將結果集數據封裝到對象中 property:對象的屬性名稱 column:外鍵 javaType:對象的類型 --> <association property="role" column="rid" javaType="role"> <id column="rid" property="rid"/> <result column="rname" property="rname"/> </association> </resultMap> <select id="queryUserAndRole" resultMap="userMap"> select * from user u left join role r on u.rid = r.rid; </select> UserMapper: <resultMap type="user" id="userMap2"> <id column="uid" property="uid"/> <result column="uname" property="uname"/> <!-- 將結果集數據封裝到對象中 property:對象的屬性名稱 column:外鍵 javaType:對象的類型 --> <association property="role" column="rid" javaType="role" select="mapper.RoleMapper.selectRole"> </association> </resultMap> <select id="queryUserAndRole2" resultMap="userMap2"> select * from user </select> RoleMapper <select id="selectRole" resultType="role"> select * from role where rid = #{rid} </select>
延遲加載
1) 延遲加載:按需加載(懶加載),只加載主查詢,需要用到子查詢信息時才去查詢。
2) <collection><association>都具有延遲加載功能。但是默認關閉。
3) 需要打開延遲加載:
<settings> <!-- 延遲加載全局開關 --> <setting name="lazyLoadingEnabled" value="true"/> <!-- 3.4.1以上為false,否則為true --> <setting name="aggressiveLazyLoading" value="false"/> </settings>
緩存
一級緩存
Mybatis中的一級緩存時默認開啟的。
在內存中一塊區域,以類似於map方式進行數據管理。
當用戶第一次查詢時,會根據sql,參數,rowbounds以及statement的id生成cacheKey,先從二級緩存中獲取數據,如果為空,將從一級緩存中根據生成key獲取value值,如果也為空,就從數據庫進行查詢,然後將key和查詢的結果放置到一級緩存中。
當用戶再次查詢時,仍舊生成cacheKey,通過key從一級緩存中獲取值,如果有值此時將直接返回不再查詢數據庫。
一級緩存是session級別的緩存。
如果執行增刪改會清空一級緩存。
二級緩存
在內存中一塊區域,以類似於map方式進行數據管理。
當用戶第一次查詢時,會根據sql,參數,rowbounds以及statement的id生成cacheKey,先從二級緩存中獲取數據,如果為空,將從一級緩存中根據生成key獲取value值,如果也為空,就從數據庫進行查詢,然後將key和查詢的結果放置到一級緩存中。
當用戶再次查詢時,仍舊生成cacheKey,通過key從一級緩存中獲取值,如果有值此時將直接返回不再查詢數據庫。
如果執行增刪改會清空二級緩存
二級緩存是跨session的緩存。
默認二級緩存關閉。
實體類必須序列化。
<cache>
//讀取配置文件轉換為流 InputStream is = Resources.getResourceAsStream("Mybatis.xml"); //創建ssf對象 SqlSessionFactory ssf = new SqlSessionFactoryBuilder().build(is); SqlSession session = ssf.openSession(true); SqlSession session2 = ssf.openSession(true); SqlSession session3 = ssf.openSession(true); //根據mapper接口生成實現類對象 BookMapper mapper = session.getMapper(BookMapper.class); BookMapper mapper2 = session2.getMapper(BookMapper.class); BookMapper mapper3 = session3.getMapper(BookMapper.class); System.out.println(mapper.queryAll()); session.close(); System.out.println(mapper2.queryAll()); session2.close(); System.out.println(mapper3.queryAll()); session3.close();
Day2 Mybatis初識(二)