【Mybatis 系列10-結合源碼解析mybatis 執行流程】html
【Mybatis 系列8-結合源碼解析select、resultMap的用法】 sql
【Mybatis 系列7-結合源碼解析核心CRUD配置及用法】數據庫
【Mybatis 系列6-結合源碼解析節點配置objectFactory、databaseIdProvider、plugins、mappers】apache
【Mybatis 系列5-結合源碼解析TypeHandler】 緩存
【Mybatis 系列4-結合源碼解析節點typeAliases】session
【Mybatis 系列3-結合源碼解析properties節點和environments節點】mybatis
上篇系列7 介紹了insert、update、delete的用法,
select無疑是咱們最經常使用,也是最複雜的,mybatis經過resultMap能幫助咱們很好地進行高級映射。
下面就開始看看select 以及 resultMap的用法:
先看select的配置:
1 <select 2 <!-- 1. id (必須配置) 3 id是命名空間中的惟一標識符,可被用來表明這條語句。 4 一個命名空間(namespace) 對應一個dao接口, 5 這個id也應該對應dao裏面的某個方法(至關於方法的實現),所以id 應該與方法名一致 --> 6 7 id="selectPerson" 8 9 <!-- 2. parameterType (可選配置, 默認爲mybatis自動選擇處理) 10 將要傳入語句的參數的徹底限定類名或別名, 若是不配置,mybatis會經過ParameterHandler 根據參數類型默認選擇合適的typeHandler進行處理 11 parameterType 主要指定參數類型,能夠是int, short, long, string等類型,也能夠是複雜類型(如對象) --> 12 parameterType="int" 13 14 <!-- 3. resultType (resultType 與 resultMap 二選一配置) 15 resultType用以指定返回類型,指定的類型能夠是基本類型,能夠是java容器,也能夠是javabean --> 16 resultType="hashmap" 17 18 <!-- 4. resultMap (resultType 與 resultMap 二選一配置) 19 resultMap用於引用咱們經過 resultMap標籤訂義的映射類型,這也是mybatis組件高級複雜映射的關鍵 --> 20 resultMap="personResultMap" 21 22 <!-- 5. flushCache (可選配置) 23 將其設置爲 true,任什麼時候候只要語句被調用,都會致使本地緩存和二級緩存都會被清空,默認值:false --> 24 flushCache="false" 25 26 <!-- 6. useCache (可選配置) 27 將其設置爲 true,將會致使本條語句的結果被二級緩存,默認值:對 select 元素爲 true --> 28 useCache="true" 29 30 <!-- 7. timeout (可選配置) 31 這個設置是在拋出異常以前,驅動程序等待數據庫返回請求結果的秒數。默認值爲 unset(依賴驅動)--> 32 timeout="10000" 33 34 <!-- 8. fetchSize (可選配置) 35 這是嘗試影響驅動程序每次批量返回的結果行數和這個設置值相等。默認值爲 unset(依賴驅動)--> 36 fetchSize="256" 37 38 <!-- 9. statementType (可選配置) 39 STATEMENT,PREPARED 或 CALLABLE 的一個。這會讓 MyBatis 分別使用 Statement,PreparedStatement 或 CallableStatement,默認值:PREPARED--> 40 statementType="PREPARED" 41 42 <!-- 10. resultSetType (可選配置) 43 FORWARD_ONLY,SCROLL_SENSITIVE 或 SCROLL_INSENSITIVE 中的一個,默認值爲 unset (依賴驅動)--> 44 resultSetType="FORWARD_ONLY">
配置看起來老是這麼多,不過實際經常使用的配置也就那麼幾個, 根據本身的須要吧,上面都已註明是否必須配置。
下面仍是針對select 及時練練手吧:
------------------------------------------------------------------------下面是針對select 的練手demo---------------------------------------------------------------------------------------
數據庫:
新增兩張表(t_course, t_student)
t_course:
t_student:
其中,1個student可選擇多個course進行學習。 咱們拿上篇文章的demo, 繼續增長後,項目目錄以下所示:
Course.java:
1 package com.dy.entity; 2 3 public class Course { 4 5 private int id; 6 private String name; 7 private int deleteFlag; 8 9 public int getId() { 10 return id; 11 } 12 public void setId(int id) { 13 this.id = id; 14 } 15 public String getName() { 16 return name; 17 } 18 public void setName(String name) { 19 this.name = name; 20 } 21 public int getDeleteFlag() { 22 return deleteFlag; 23 } 24 public void setDeleteFlag(int deleteFlag) { 25 this.deleteFlag = deleteFlag; 26 } 27 28 }
Student.java:
1 package com.dy.entity; 2 3 import java.util.List; 4 5 public class Student { 6 7 private int id; 8 private String idCard; 9 private String name; 10 private List<Course> courseList; 11 private int deleteFlag; 12 13 public Student(int id, String idCard, String name, List<Course> courseList, int deleteFlag) { 14 this.id = id; 15 this.idCard = idCard; 16 this.name = name; 17 this.courseList = courseList; 18 this.deleteFlag = deleteFlag; 19 } 20 21 public int getId() { 22 return id; 23 } 24 public void setId(int id) { 25 this.id = id; 26 } 27 public String getIdCard() { 28 return idCard; 29 } 30 public void setIdCard(String idCard) { 31 this.idCard = idCard; 32 } 33 public String getName() { 34 return name; 35 } 36 public void setName(String name) { 37 this.name = name; 38 } 39 public List<Course> getCourseList() { 40 return courseList; 41 } 42 public void setCourseList(List<Course> courseList) { 43 this.courseList = courseList; 44 } 45 public int getDeleteFlag() { 46 return deleteFlag; 47 } 48 public void setDeleteFlag(int deleteFlag) { 49 this.deleteFlag = deleteFlag; 50 } 51 }
CourseDao.java:
1 package com.dy.dao; 2 3 import com.dy.entity.Course; 4 5 public interface CourseDao { 6 7 public Course findCourseById(int courseId); 8 9 } 10 11 12 StudentDao.java: 13 package com.dy.dao; 14 15 16 import com.dy.entity.Student; 17 18 public interface StudentDao { 19 20 public Student findStudentById(String idCard); 21 }
courseDao.xml:
1 <mapper namespace="com.dy.dao.CourseDao"> 2 3 <!-- 4 1.此處直接將resultType 設置爲course, 一看就知道我設置了別名吧,若是沒有設置別名,那麼resultType = com.dy.entity.Course。 5 2.可能細心的你會發現:Course.java中的屬性名與數據庫字段名不一致,下面,我就在sql語句中用了as, 使之匹配,固然方法不止一種, 6 在學習了resultMap以後,你能看到一種更直觀優雅的方式去將javabean中的屬性與數據庫字段名保持一致 7 3.findCourseById 與CourseDao中findCourseById方法對應, 那麼傳入的參數名稱以及類型也應該保持對應關係。 8 4.能夠看到,在sql語句中,經過#{}表達式能夠獲取參數。 9 5.下面這條sql語句,實際上的形式是怎麼樣的?還記得以前說過,mybatis默認爲preparedStatement吧,那麼,用咱們jdbc代碼來看,它其實就是: 10 select course_id as id, course_name as name, course_delete_flg as deleteFlag from t_course where course_id=? 11 --> 12 <select id="findCourseById" resultType="course" > 13 select course_id as id, course_name as name, course_delete_flg as deleteFlag from t_course where course_id=#{courseId} 14 </select> 15 16 </mapper>
CourseDaoTest.java:
1 package com.dy.dao; 2 3 import java.io.IOException; 4 5 import org.apache.ibatis.io.Resources; 6 import org.apache.ibatis.session.SqlSession; 7 import org.apache.ibatis.session.SqlSessionFactory; 8 import org.apache.ibatis.session.SqlSessionFactoryBuilder; 9 import org.junit.Test; 10 11 import com.dy.entity.Course; 12 13 public class CourseDaoTest { 14 15 @Test 16 public void findCourseById() { 17 SqlSessionFactory sqlSessionFactory = getSessionFactory(); 18 SqlSession sqlSession = sqlSessionFactory.openSession(); 19 CourseDao courseDao = sqlSession.getMapper(CourseDao.class); 20 Course course = courseDao.findCourseById(1); 21 } 22 23 24 //Mybatis 經過SqlSessionFactory獲取SqlSession, 而後才能經過SqlSession與數據庫進行交互 25 private static SqlSessionFactory getSessionFactory() { 26 SqlSessionFactory sessionFactory = null; 27 String resource = "mybatis-conf.xml"; 28 try { 29 sessionFactory = new SqlSessionFactoryBuilder().build(Resources 30 .getResourceAsReader(resource)); 31 } catch (IOException e) { 32 e.printStackTrace(); 33 } 34 return sessionFactory; 35 } 36 }
上面的示例,咱們針對course, 簡單演示了 select的用法, 不過有個問題值得思考: 一個student能夠對應多個course,
那麼,在mybatis中如何處理這種一對多, 甚至於多對多,一對一的關係呢?
這兒,就不得不提到 resultMap 這個東西, mybatis的resultMap功能可謂十分強大,可以處理複雜的關係映射,
那麼resultMap 該怎麼配置呢?
resultMap的配置:
1 <!-- 2 1.type 對應類型,能夠是javabean, 也能夠是其它 3 2.id 必須惟一, 用於標示這個resultMap的惟一性,在使用resultMap的時候,就是經過id指定 4 --> 5 <resultMap type="" id=""> 6 7 <!-- id, 惟一性,注意啦,這個id用於標示這個javabean對象的惟一性, 不必定會是數據庫的主鍵(不要把它理解爲數據庫對應表的主鍵) 8 property屬性對應javabean的屬性名,column對應數據庫表的列名 9 (這樣,當javabean的屬性與數據庫對應表的列名不一致的時候,就能經過指定這個保持正常映射了) 10 --> 11 <id property="" column=""/> 12 13 <!-- result與id相比, 對應普通屬性 --> 14 <result property="" column=""/> 15 16 <!-- 17 constructor對應javabean中的構造方法 18 --> 19 <constructor> 20 <!-- idArg 對應構造方法中的id參數 --> 21 <idArg column=""/> 22 <!-- arg 對應構造方法中的普通參數 --> 23 <arg column=""/> 24 </constructor> 25 26 <!-- 27 collection,對應javabean中容器類型, 是實現一對多的關鍵 28 property 爲javabean中容器對應字段名 29 column 爲體如今數據庫中列名 30 ofType 就是指定javabean中容器指定的類型 31 --> 32 <collection property="" column="" ofType=""></collection> 33 34 <!-- 35 association 爲關聯關係,是實現N對一的關鍵。 36 property 爲javabean中容器對應字段名 37 column 爲體如今數據庫中列名 38 javaType 指定關聯的類型 39 --> 40 <association property="" column="" javaType=""></association> 41 </resultMap>
好啦,知道resutMap怎麼配置後,我們當即接着上面的demo來練習一下吧:
------------------------------------------------------------------下面是用resultMap處理一對多關係的映射的示例-------------------------------------------------------------
一個student對應多個course, 典型的一對多,
我們就來看看mybatis怎麼配置這種映射吧: studentDao.xml:
1 <mapper namespace="com.dy.dao.StudentDao"> 2 3 <!-- 這兒定義一個resultMap --> 4 <resultMap type="student" id="studentMap"> 5 6 <!-- 7 數據庫中主鍵是id, 可是我這兒倒是指定idCard爲主鍵,爲何? 8 剛剛講了,id用來表示惟一性, 咱們能夠認爲只要idCard同樣,那麼他就是同一個學生。 9 若是此處用數據庫中id, 那麼mybatis將會認爲數據庫中每條記錄都是一個student, 這顯然不符合邏輯 10 --> 11 <id property="idCard" column="stu_id_card"/> 12 <result property="id" column="stu_id"/> 13 <result property="name" column="stu_name"/> 14 <result property="deleteFlag" column="stu_delete_flg"/> 15 16 <!-- 17 這兒就是實現一對多的關鍵。 18 在Student中,courseList爲List<Course>, 所以,ofType也應該與之對應(固然,我用了別名,否則要蛋疼的寫全名了)。 19 collection的子標籤是在指定Course的映射關係(因爲Course的javabean的屬性名與數據庫的列名不一致) 20 --> 21 <collection property="courseList" column="stu_course_id" ofType="Course"> 22 <id property="id" column="course_id"/> 23 <result property="name" column="course_name"/> 24 <result property="deleteFlag" column="course_delete_flg"/> 25 </collection> 26 </resultMap> 27 28 <!-- 這兒將返回類型設置成了上面指定的studentMap --> 29 <select id="findStudentById" resultMap="studentMap"> 30 SELECT s.*, c.* FROM t_student s LEFT JOIN t_course c ON s.stu_course_id=c.course_id WHERE s.stu_id_card=#{idCard} 31 </select> 32 33 </mapper>
StudentDaoTest.java:
1 package com.dy.dao; 2 3 import java.io.IOException; 4 import java.util.List; 5 6 import org.apache.ibatis.io.Resources; 7 import org.apache.ibatis.session.SqlSession; 8 import org.apache.ibatis.session.SqlSessionFactory; 9 import org.apache.ibatis.session.SqlSessionFactoryBuilder; 10 import org.junit.Test; 11 12 import com.dy.entity.Course; 13 import com.dy.entity.Student; 14 15 public class StudentDaoTest { 16 17 @Test 18 public void findCourseById() { 19 SqlSessionFactory sqlSessionFactory = getSessionFactory(); 20 SqlSession sqlSession = sqlSessionFactory.openSession(); 21 StudentDao studentDao = sqlSession.getMapper(StudentDao.class); 22 Student student = studentDao.findStudentById("20140101"); 23 List<Course> courseList = student.getCourseList(); 24 for (Course course: courseList) { 25 System.out.println(course.getId() + " " + course.getName()); 26 } 27 } 28 29 30 //Mybatis 經過SqlSessionFactory獲取SqlSession, 而後才能經過SqlSession與數據庫進行交互 31 private static SqlSessionFactory getSessionFactory() { 32 SqlSessionFactory sessionFactory = null; 33 String resource = "mybatis-conf.xml"; 34 try { 35 sessionFactory = new SqlSessionFactoryBuilder().build(Resources 36 .getResourceAsReader(resource)); 37 } catch (IOException e) { 38 e.printStackTrace(); 39 } 40 return sessionFactory; 41 } 42 }
相信經過以上demo, 你們也可以使用mybatis的select 和 resultMap的用法了。
上面demo只演示了一對多的映射,其實多對1、多對多也與它相似,有興趣的能夠本身動手再作作。