mybatis多表查詢之多對多關係查詢的實現-xml方式
Mybatis對於多對多關係下的查詢提供了集合(collection)的概念來解決,collection屬性是resultMap高階結果對映的子集,首先,在本例中我們使用的是集合元素來解決多對多的查詢。 然後你會注意到有一個新的 “ofType” 屬性。這個屬性非常重要,它用來將 JavaBean(或欄位)屬性的型別和集合儲存的型別區分開來。在集合中ofType指的是集合中元素的型別。
首先介紹一下Demo情況:
- 實體類:User(使用者)類和Role(角色)類,類中的屬性在後面程式碼中貼出
- 關係:一個使用者可以有多個角色,一個角色可以賦予多個使用者中
- 資料庫表結構:使用者表、角色表、中間表(用於儲存使用者和角色的關係)
- 本例中實現查詢的目標:查詢使用者時同時獲取使用者所擁有的角色的資訊(當查詢角色時同時獲取角色所屬使用者的資訊的情況和下面的例子原理一樣,主要是修改select中的sql語句)
1.使用者實體類以及角色實體類
public class User implements Serializable{ private Integer id; private String username; private Date birthday; private String sex; private String address; private List<Role> roles; get和set方法省略 ...... } public class Role implements Serializable{ private Integer roleId; private String roleName; private String roleDesc; private List<User> users; get和set方法省略 ...... }
這裡主要是增加使用者所擁有的角色的List屬性和角色所屬使用者的List屬性,後面做resultMap結果對映的時候使用。
2.資料庫表結構
DROP TABLE IF EXISTS user; CREATE TABLE user ( id INT(11) NOT NULL auto_increment, username VARCHAR(32) NOT NULL COMMENT '使用者名稱稱', birthday datetime default NULL COMMENT '生日', sex char(1) default NULL COMMENT '性別', address varchar(256) default NULL COMMENT '地址', PRIMARY KEY (id) )ENGINE=InnoDB default CHARSET=utf8 INSERT INTO `user` VALUES ('41', '老王', '2018-02-27 17:47:08', '男', '石家莊'); INSERT INTO `user` VALUES ('45', '老李', '2018-02-27 17:47:08', '男', '石家莊'); INSERT INTO `user` VALUES ('46', '老郭', '2018-02-27 17:47:08', '男', '石家莊'); INSERT INTO `user` VALUES ('47', 'mde', '2019-06-26 15:04:25', '女', '河南'); INSERT INTO `user` VALUES ('48', 'nan', '2019-08-01 15:04:54', '女', '合肥'); DROP TABLE IF EXISTS role; CREATE TABLE role( ID int(11) NOT NULL COMMENT '編號', ROLE_NAME VARCHAR(30) DEFAULT NULL COMMENT '角色名稱', ROLE_DESC VARCHAR(60) DEFAULT NULL COMMENT '角色描述', PRIMARY KEY (ID) )ENGINE=INNODB DEFAULT CHARSET=utf8 INSERT INTO role (ID,ROLE_NAME,ROLE_DESC) VALUES (1,'院長','管理整個學院'),(2,'總裁','管理整個公司'),(3,'校長','管理整個學校'); DROP TABLE IF EXISTS user_role; CREATE TABLE user_role( UID int(11) NOT NULL COMMENT '使用者編號', RID INT(11) NOT NULL COMMENT '角色編號', PRIMARY KEY (UID,RID), CONSTRAINT FK_Reference_10 FOREIGN KEY(RID) REFERENCES role(ID), CONSTRAINT FK_Reference_9 FOREIGN KEY(UID) REFERENCES user(id) )ENGINE=INNODB DEFAULT CHARSET=utf8; INSERT INTO user_role(UID,RID) VALUES(41,1),(45,1),(41,2);
這裡主要是增加了中間表。
3.在UserDao介面中宣告查詢所有使用者的方法findAll();
/** * 查詢所有的使用者同時查詢出所擁有的角色的資訊 * * @return */ List<User> findAll();
4.在UserDao.xml中配置findAll()方法
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd"> <mapper namespace="com.example.dao.UserDao"> <resultMap id="userMap" type="com.example.domain.User"> <id property="id" column="id"/> <result property="username" column="username"/> <result property="birthday" column="birthday"/> <result property="sex" column="sex"/> <result property="address" column="address"/> <collection property="roles" ofType="com.example.domain.Role" resultMap="roleMap"/> </resultMap> <resultMap id="roleMap" type="com.example.domain.Role"> <id property="roleId" column="rid"/> <result property="roleName" column="ROLE_NAME"/> <result property="roleDesc" column="ROLE_DESC"/> </resultMap> <select id="findAll" resultMap="userMap"> SELECT u.*,r.ID as rid,r.ROLE_DESC,r.ROLE_NAME FROM user u LEFT OUTER JOIN user_role ur on u.id = ur.UID LEFT OUTER JOIN role r on ur.RID = r.ID </select> </mapper>
實現多對多關係查詢的主要工作都放在了這裡,首先通過resultMap 宣告使用者類的結果對映,id以及result等標籤就是User類中的基本屬性,User類中的角色屬性roles通過collection集合標籤來對映到結果集中,<collection property="roles" ofType="com.example.domain.Role" resultMap="roleMap"/>,property對應User類中宣告的roles屬性,ofType用於標識集合中元素的型別,resultMap用於引用其他的結果對映來說明集合中元素的屬性,在這裡為roleMap。如果roleMap不在其他地方使用,也可以直接將角色的屬性直接配置在collection屬性的子集裡,如以下形式也可以使用。
<resultMap id="userMap" type="com.example.domain.User"> <id property="id" column="id"/> <result property="username" column="username"/> <result property="birthday" column="birthday"/> <result property="sex" column="sex"/> <result property="address" column="address"/> <!--<collection property="roles" ofType="com.example.domain.Role" resultMap="roleMap"/>--> <collection property="roles" ofType="com.example.domain.Role">
<!--這裡的rid是role表中的id,在select語句中為了防止id欄位在兩個表中都出現導致的重複,所以給role的欄位id 起了別名 注意要與select中的別名保持一致--> <id property="roleId" column="rid"/> <result property="roleName" column="ROLE_NAME"/> <result property="roleDesc" column="ROLE_DESC"/> </collection> </resultMap>
select中的SQL查詢語句解釋:
<select id="findAll" resultMap="userMap"> SELECT u.*,r.ID as rid,r.ROLE_DESC,r.ROLE_NAME FROM user u LEFT OUTER JOIN user_role ur on u.id = ur.UID LEFT OUTER JOIN role r on ur.RID = r.ID </select>
u.*:查詢USER表中所有的屬性
r.ID as rid:對於role表中的id起一個別名rid
user u LEFT OUTER JOIN user_role ur on u.id = ur.UID:前面的表左連線後面的表,並且連線條件是User表中的id與User_role表中的uid相等
5.測試程式碼
1 public class UserDaoTest { 2 private InputStream in; 3 private SqlSession session; 4 5 private UserDao userDao; 6 private SqlSessionFactory factory; 7 @Before 8 public void init()throws Exception{ 9 //獲取配置檔案 10 in = Resources.getResourceAsStream("SqlMapConfig.xml"); 11 //獲取工廠 12 factory = new SqlSessionFactoryBuilder().build(in); 13 14 session = factory.openSession(); 15 16 userDao = session.getMapper(UserDao.class); 17 } 18 @After 19 public void destory()throws Exception{ 20 session.commit(); 21 session.close(); 22 in.close(); 23 } 24 @Test 25 public void findAllTest(){ 26 List<User> userList = userDao.findAll(); 27 for (User user: userList){ 28 System.out.println("每個使用者的資訊"); 29 System.out.println(user); 30 System.out.println(user.getRoles()); 31 } 32 }View Code
6.測試結果
&n