在真實的業務場景中,使用resultType進行輸出映射,只有查詢出來的列名和pojo(實體bean)中的屬性名一致,該列才可以映射成功。簡單來說也就是你的數據庫字段和JavaBean里的字段名稱必須一致才能映射成功。
當JavaBean中的字段名和數據庫字段名稱有不同的時候,或者是多表查詢的時候,一般會使用resultMap。
什么是resultMap
resultMap是Mybatis最強大的元素,它可以將查詢到的復雜數據(比如查詢到幾個表中數據)映射到一個結果集當中。
resultMap的作用
resultMap的作用是定義映射規則、級聯的更新、定制類型轉化器等。resultMap定義的主要是一個結果集的映射關系,也就是sql到java bean的映射關系定義,它也支持級聯等特性。
resultMap的元素構成
resultMap元素的子元素:
<resultMap> <constructor> <idArg/> <arg> </constructor> <id/> <result/> <association/> <collection/> <discriminator> <case/> </discriminator> </resultMap>
resultMap的語法
<!--column不做限制,可以為任意表的字段,而property須為type 定義的pojo屬性--> <resultMap id="唯一的標識" type="映射的pojo對象"> <id column="表的主鍵字段,或者可以為查詢語句中的別名字段" jdbcType="字段類型" property="映射pojo對象的主鍵屬性" /> <result column="表的一個字段(可以為任意表的一個字段)" jdbcType="字段類型" property="映射到pojo對象的一個屬性(須為type定義的pojo對象中的一個屬性)"/> <association property="pojo的一個對象屬性" javaType="pojo關聯的pojo對象"> <id column="關聯pojo對象對應表的主鍵字段" jdbcType="字段類型" property="關聯pojo對象的主席屬性"/> <result column="任意表的字段" jdbcType="字段類型" property="關聯pojo對象的屬性"/> </association> <!-- 集合中的property須為oftype定義的pojo對象的屬性--> <collection property="pojo的集合屬性" ofType="集合中的pojo對象"> <id column="集合中pojo對象對應的表的主鍵字段" jdbcType="字段類型" property="集合中pojo對象的主鍵屬性" /> <result column="可以為任意表的字段" jdbcType="字段類型" property="集合中的pojo對象的屬性" /> </collection> </resultMap>
如果collection標簽是使用嵌套查詢,格式如下:
<collection column="傳遞給嵌套查詢語句的字段參數" property="pojo對象中集合屬性" ofType="集合屬性中的pojo對象" select="嵌套的查詢語句" > </collection>
注意:<collection>標簽中的column:要傳遞給select查詢語句的參數,如果傳遞多個參數,格式為column= ” {參數名1=表字段1,參數名2=表字段2} ;
resultMap的應用
比如,數據庫中字段名稱為id,name,age,sex 而對應java代碼中pojo的屬性名分別為id,username,age,sex。可以看出姓名列不一致,這個時候就需要使用resultMap來將字段名和屬性名對應起來,進行手動配置封裝,將結果映射到pojo中。
<!-- resultMap最終還是要將結果映射到pojo上,type就是指定映射到哪一個pojo --> <!-- id:設置ResultMap的id --> <resultMap type="user" id="userMap"> <!-- 定義主鍵 ,非常重要。如果是多個字段,則定義多個id --> <!-- property:pojo里的屬性名 column:數據庫中的列名 --> <id property="id" column="id" /> <!-- 定義普通屬性 property:pojo里的屬性名 column:數據庫中的列名--> <result property="username" column="name" /> <result property="age" column="age" /> <result property="sex" column="sex" /> </resultMap> <!-- resultMap:填入配置的resultMap標簽的id值 --> <select id="findUser" resultMap="userMap"> select id,name,age,sex from user </select>
級聯
Mybatis的級聯操作主要是針對一對多、多對一和多對多的情況而設定的。級聯是在resultMap標簽中配置的。級聯並不是必須的,好處就是獲取關聯數據便捷,但如果級聯過多會增加系統的復雜度,同時降低系統的性能。所以記錄超過3層時,就不要考慮使用級聯了,因為這樣會造成多個對象的關聯,導致系統的耦合、負載和難以維護。
一對一
業務場景:訂單用戶,一條訂單信息只能對應一個用戶,此為一對一。做法如下:
1. 改造訂單的pojo類:
(添加User屬性--User屬性是一個引用類型,用於存儲關聯查詢的用戶信息,因為關聯關系是一對一,所以只需要添加單個屬性即可)
//訂單類 pulic class Order{ //原order屬性 private int id; private Integer userId; private String number; private Date createtime; private String note; //新加user屬性 private User user; //下面省略get和set方法 } //用戶信息類 pulic void User{ private int id; private String username; private String address; //下面省略get和set方法 }
2. 修改mapper.xml配置文件
(使用resultMap和association標簽來實現一對一)
<resultMap type="order" id="orderUserResultMap"> <!-- 第一步:配置Order類的對應關系 --> <!-- property:pojo里的屬性名 column:數據庫中的列名 --> <id property="id" column="id" /> <result property="userId" column="user_id" /> <result property="number" column="number" /> <result property="createtime" column="createtime" /> <result property="note" column="note" /> <!-- 第二步:配置User類的對應關系 --> <!-- association :配置一對一屬性 property:order里面的User屬性名 javaType:屬性類型--> <association property="user" javaType="user"> <!-- id:聲明主鍵,表示user_id是關聯查詢對象的唯一標識 --> <!-- 簡單說就是:id標簽:(property:user表的主鍵名稱 column:對應Order表的外鍵名稱) result標簽下的都是user表的內容--> <id property="id" column="user_id" /> <result property="username" column="username" /> <result property="address" column="address" /> </association> </resultMap> <!-- 一對一關聯,查詢訂單,訂單內部包含用戶屬性 --> <select id="queryOrderUserResultMap" resultMap="orderUserResultMap"> SELECT a.id,a.user_id,a.number,a.createtime,a.note,b.username,b.address from order a left join user b on a.user_id = b.id </select>
3. 測試代碼:
@Test public void testQueryOrderUserResultMap() { // mybatis和spring整合,整合之后,交給spring管理 SqlSession sqlSession = this.sqlSessionFactory.openSession(); // 創建Mapper接口的動態代理對象,整合之后,交給spring管理 UserMapper userMapper = sqlSession.getMapper(UserMapper.class); // 使用userMapper執行根據條件查詢用戶,結果封裝到Order類中 List<Order> list = userMapper.queryOrderUserResultMap(); for (Order o : list) { System.out.println(o); } // mybatis和spring整合,整合之后,交給spring管理 sqlSession.close(); }
一對多
業務場景:訂單用戶,一個用戶對應多條訂單信息,此為一對多。做法如下:
1. 改造用戶的pojo類:
(添加訂單集合屬性)
//訂單類 pulic class Order{ private int id; private Integer userId; private String number; private Date createtime; private String note; //下面省略get和set方法 } //用戶信息類 pulic void User{ //原用戶屬性 private int id; private String username; private String address; //新加訂單集合屬性 private List<Order> orders; //下面省略get和set方法 }
2. 修改mapper.xml配置文件
(使用resultMap和collection標簽來實現一對多)
<!-- 因為主要查詢的是user 所以先配置User類的結果 --> <resultMap type="user" id="userOrderResultMap"> <!-- 第一步:配置User類的對應關系 --> <id property="id" column="id" /> <result property="username" column="username" /> <result property="sex" column="sex" /> <result property="address" column="address" /> <!-- 第二步:配置order類的對應關系 --> <!-- property:填寫pojo類中集合類類屬性的名稱 javaType:填寫集合類型的名稱 ofType:list中內容的類型 --> <collection property="orders" javaType="list" ofType="order"> <!-- 配置主鍵,是關聯Order的唯一標識 這里要注意oid 是因為下面select標簽的sql中給order的id起了別名 叫做oid--> <id property="id" column="oid" /> <result property="number" column="number" /> <result property="createtime" column="createtime" /> <result property="note" column="note" /> </collection> </resultMap> <!-- 一對多關聯,查詢訂單同時查詢該用戶下的訂單 --> <select id="queryUserOrder" resultMap="userOrderResultMap"> SELECT a.id,a.username,a.address,a.sex,b.id oid,b.number,b.createtime,b.note from user a left join order b on a.id = b.user_id </select>
當然也有更多一級的一對多:collection中有collection和association,這里不多介紹。
多對多
業務場景:每個老師有多個學生,每個學生又有多個老師,此為多對多。用法如下:
1. 首先涉及到三張表:學生表(student)、教師表(teacher)、學生和教師關系表(tu_teach_rel)
public class Student{ //學生表原屬性 private String id; private String name; private int age; private Gender gender; //學生表新加屬性 private List<Teacher> teachers; //下面省略get和set方法 } public class Teacher{ //教師表原屬性 private int id; private String name; private Gender gender; private Subject subject; private String degree; //教師表新加屬性 private List<Student> students; //下面省略get和set方法 } public class stu_teach_rel{ //學生教師關系表 private int id; private int stu_id; private int teach_id; //這里不需要加東西 //下面省略get和set方法 }
2. mapper.xml配置文件
<mapper namespace="com.yihaomen.mybatis.dao.StudentMapper"> <resultMap id="studentMap" type="Student"> <id property="id" column="id" /> <result property="name" column="name" /> <result property="age" column="age" /> <result property="gender" column="gender" typeHandler="org.apache.ibatis.type.EnumOrdinalTypeHandler" /> </resultMap> <resultMap id="collectionMap" type="Student" extends="studentMap"> <collection property="teachers" ofType="Teacher"> <id property="id" column="teach_id" /> <result property="name" column="tname"/> <result property="gender" column="tgender" typeHandler="org.apache.ibatis.type.EnumOrdinalTypeHandler"/> <result property="subject" column="tsubject" typeHandler="org.apache.ibatis.type.EnumTypeHandler"/> <result property="degree" column="tdegree" javaType="string" jdbcType="VARCHAR"/> </collection> </resultMap> <select id="selectStudents" resultMap="collectionMap"> SELECT s.id, s.name, s.gender, t.id teach_id, t.name tname, t.gender tgender, t.subject tsubject, t.degree tdegree FROM student s LEFT JOIN stu_teach_rel str ON s.id = str.stu_id LEFT JOIN teacher t ON t.id = str.teach_id </select> </mapper>
總結:
一對一可以通過<association>實現,一對多和多對多通過<collection>實現。
參考:
1. https://www.cnblogs.com/kenhome/p/7764398.html
2. https://blog.csdn.net/qq_42780864/article/details/81429114
3. https://blog.csdn.net/lks1139230294/article/details/88087470
4. https://www.jb51.net/article/126584.htm
持續更新!!!
