1. 程式人生 > >Mybatis框架的使用之四(resultMap的使用)

Mybatis框架的使用之四(resultMap的使用)

絕大多數情況下,一條完整的資訊至少分別來自兩張或以上的表,連表查詢非常常見,這種情況下可以使用resultMap屬性

1、使用resultMap實現簡單結果對映:

user表:在這裡插入圖片描述

role表:
在這裡插入圖片描述

user表中的userRole是外來鍵,對應role表中的id
需求:通過userName和userRole,查詢到符合條件的使用者和其RoleName
在這裡,使用者資訊來自user表,roleName來自role表。我們採用封裝物件的傳參的方式進行查詢。首先可以修改pojo的User類,新增一個userRoleName的String屬性和相應的setter、getter方法

然後在mapper檔案中新建一個select標籤:

    <select id="getUserList" resultMap="userList" parameterType="User">
			select u.*,r.roleName from smbms_user AS u,smbms_role AS r where u.userName
			like CONCAT('%',#{userName},'%') AND  u.userRole = #{userRole}
			AND u.userRole = r.id
	</select>

這裡沒有使用resultType標籤了,而是換成了resultMap,它的值由我們自定義。
然後,在剛剛編寫完成select標籤外,建立一個resultMap標籤:

 <!--id與使用resultMap屬性的標籤值一致,type是返回型別-->
  <resultMap id="userList" type="User">
        <!--column是表的列名 property是查出來的欄位值要賦給的實體物件的屬性名稱-->
        <!--意味著我們採用自定義的方式進行對映-->
        <result property="id" column="id"></result>
        <result property="userCode" column=
"userCode"></result> <result property="userName" column="userName"></result> <!--在這裡把role表的roleName列的值賦給了User類的userRoleName屬性--> <result property="userRoleName" column="roleName"></result> </resultMap>

介面方法沒有什麼新變化:

 List<User> getUserList(User user);

測試類:

public void getUserList() {
        SqlSession sqlSession = null;
        List<User> list;
        User u = new User();
        u.setUserName("趙");
        u.setUserRole(2);
        try {
            sqlSession = MyBatisUtils.getSQLSession();
            list = sqlSession.getMapper(UserMapper.class).getUserList(u);
            for (User user : list)
                logger.debug("UserCode:" + user.getUserCode() + "\tUserRoleName:" + user.getUserRoleName() + "\tUserName:"
                        + user.getUserName() + "\tUserAddress:"
                        + user.getAddress());

        } catch (Exception e) {
            // TODO: handle exception
            e.printStackTrace();
        } finally {
            MyBatisUtils.closeSqlSession(sqlSession);
        }
    }

可以得到的查詢結果是:
UserCode:zhaomin UserRoleName:經理 UserName:趙敏 UserAddress:北京市昌平區天通苑3區12號樓

引申說明:這裡是涉及到一個叫做自動對映級別(autoMappingBehavior)的屬性,設定的位置是在mybatis-config.xml核心配置檔案中標籤中的一個,一共三個value,分別是"NONE" “FULL” 和 “PARTIAL”
FULL:自動匹配所有屬性
NONE:禁止自動匹配(只能依靠自定義resultMap,沒有定義的都會是null)
PARTIAL:預設,自動匹配所有屬性,內部巢狀除外

	<settings>
		<setting name="logImpl" value="LOG4J" />
		<setting name="autoMappingBehavior" value="FULL" />
	</settings>

resultType和resultMap的區別:

resultType直接表示了返回型別,可以是基本資料型別,也可以是複雜資料型別。
resultMap,是對外部resultMap的引用,用於資料庫欄位資訊與物件屬性不一致的情況,可以完成較複雜的聯合查詢。

二者本質上都是Map資料結構,不要同時使用。

2、使用resultMap實現高階結果對映

resultMap屬性
id:resultMap的唯一標識
type:Java實體類

resultMap子元素:
id:一般對應資料庫中該行的主鍵id,設定此項可提高mybatis效能
result:對映到JavaBean的某個“簡單型別”屬性
association:對映到JavaBean的某個“複雜型別”屬性,比如JavaBean類
collection:對映到JavaBean的某個“複雜型別”屬性,比如集合

association:
複雜的型別關聯,一對一
內部巢狀:對映一個巢狀JavaBean屬性(一個JavaBean作為另一個JavaBean的屬性)
屬性:

property:對映資料庫列的實體物件的屬性
javaType:完整Java類名或者別名
resultMap:引用外部resultMap

子元素:

  1. id
  2. result:
    Property:對映資料庫列的實體物件的屬性
    column:資料庫列名或者別名

應用情景:多表查詢多個欄位,如果每一個欄位都要"複製"到同一個JavaBean實體類中,非常繁瑣。這種情況可以使用JavaBean的巢狀。
例如一個user類,含有一個role類的屬性。這樣相當於把role類的所有屬性都封裝並放入了user類。

先新增一個介面方法:通過角色id獲得相應的使用者列表

    List<User> getUserListByRoleId(@Param("userRole") Integer roleId);

mapper檔案:

    <resultMap type="User" id="userRoleResult">
        <id property="id" column="id"/>
        <result property="userCode" column="userCode"/>
        <result property="userName" column="userName"/>
        <result property="userRole" column="userRole"/>
        <association property="role" javaType="Role" resultMap="roleResult"/>
    </resultMap>

    <resultMap type="Role" id="roleResult">
        <id property="id" column="r_id"/>
        <result property="roleCode" column="roleCode"/>
        <result property="roleName" column="roleName"/>
    </resultMap>

    <select id="getUserListByRoleId" parameterType="Integer" resultMap="userRoleResult">
        select u.*,r.id as r_id,r.roleCode,r.roleName from smbms_user AS u,smbms_role AS r
        where u.userRole = #{userRole} and u.userRole = r.id
    </select>

這裡相對複雜,解釋如下:
首先建立了select語句,因為是連表查詢,因此通過resultMap ="userRoleResult"進行第一次對映。
在userRoleResult這個resultMap中,返回的物件其實依舊是User,
然後 < id property=“id” column=“id”/ >中的第一個id就是User類中的id屬性名,就叫id。column中的id是對應的列名或者別名,因為在查詢語句中沒有起別名,所以就是user表的id列的列名:id。

然後是常規的result自定義對映,如果在mybatis-config.xml配置檔案中將autoMappingBehavior的value設定為"FULL"的話,所有的result對映都可以不做,因為會進行全域性的同名自動對映。
然後需要新增
< association property=“role” javaType=“Role” resultMap=“roleResult”/ >這個標籤。因為在User這個類中嵌套了Role,所以需要再次的resultMap,property就是在JavaBean中要對映的JavaBean的屬性名,在這裡就是User類中的Role role;屬性名是role,javaType就是要對映的類的完整限定名,因為在配置檔案中已經配置了<typeAliases> <package name="cn.smbms.pojo" /> </typeAliases>,所以這裡直接寫Role就可以。然後要對Role再做對映配置,所以再次resultMap到roleResult

在id為roleResult的resultMap中,返回的型別type自然是Role,然後這裡面的子節點 < id property=“id” column=“r_id”/ >property的id就是Role這個類中id的屬性名,就是id,而column則是表中的列名,因為在sql語句中起了別名,因此是r_id
下面依舊是常規的result對映…

全部完成後的測試方法:

 public void getUserListByRoleIdTest() {
        SqlSession sqlSession = null;
        List<User> userList = new ArrayList<>();
        Integer roleId = 3;
        try {
            sqlSession = MyBatisUtils.getSQLSession();
            userList = sqlSession.getMapper(UserMapper.class).getUserListByRoleId(roleId);
        } catch (Exception e) {
            // TODO: handle exception
            e.printStackTrace();
        } finally {
            MyBatisUtils.closeSqlSession(sqlSession);
        }
        logger.debug("getUserListByRoleIdTest userList.size : " + userList.size());
        for (User user : userList) {
            logger.debug("userList =====> userName: " + user.getUserName()
                    + ", userPassword: " + user.getUserPassword()
                    + ", Role: " + user.getRole().getId() + " --- "
                    + user.getRole().getRoleCode() + " --- " + user.getRole().getRoleName());
        }
    }

執行結果沒有問題:
在這裡插入圖片描述

以上就是association在處理一對一情況下的使用,而在處理一對多的時候,就需要使用另一個屬性:collection

collection:
複雜型別集合,一對多
內部巢狀:對映一個巢狀結果集到一個列表
屬性:
property:對映資料庫列的實體物件的屬性
ofType:完整Java類名或者別名(集合所包括的型別)
resultMap:引用外部resultMap

子元素:
id
result:
property:對映資料庫列的實體物件的屬性
column:資料庫列名或者別名

模擬需求:獲取指定id的使用者資訊和地址列表(同一使用者有多個不同地址)

這裡需要引入一張address表,同時建立Address的pojo類
在這裡插入圖片描述

完成後,需要在User類中新增一個List集合,泛型為Address,並生成setter和getter方法

    private List<Address> addressList;//使用者地址列表
    
    public List<Address> getAddressList() {
        return addressList;
    }
    public void setAddressList(List<Address> addressList) {
        this.addressList = addressList;
    }

然後在介面類中增加方法:

  List<User> getAddressListByUserId(@Param("id") Integer userId);

mapper檔案:

    <resultMap type="User" id="userAddressResult">
        <id property="id" column="id"/>
        <result property="userCode" column="userCode"/>
        <result property="userName" column="userName"/>
        <collection property="addressList" ofType="Address" resultMap="addressResult"/>
    </resultMap>

    <resultMap type="Address" id="addressResult">
        <id property="id" column="a_id"/>
        <result property="postCode" column="postCode"/>
        <result property="tel" column="tel"/>
        <result property="contact" column="contact"/>
        <result property="addressDesc" column="addressDesc"/>
    </resultMap>

    <select id="getAddressListByUserId" parameterType="Integer" resultMap="userAddressResult">
        select u.*,a.id as a_id,a.contact,a.addressDesc,a.postCode,a.tel,a.userId
        from smbms_user u LEFT JOIN smbms_address a ON u.id = a.userId where u.id=#{id}
    </select>

這裡的用法跟association基本相似,不同的是< collection property=“addressList” ofType=“Address” resultMap=“addressResult”/ >

這裡的property指的是在JavaBean中所對映的資料庫類的實體物件的屬性名,這個屬性是 private List< Address> addressList; 屬性名就是addressList。
ofType是完整的類名或別名,也就是集合所包含的型別。依舊可以直接使用別名Address。
id、result的配置與association中的一致

測試方法:

public void getAddressListByUserIdTest() {
        SqlSession sqlSession = null;
        List<User> userList = new ArrayList<>();
        Integer userId = 1;
        try {
            sqlSession = MyBatisUtils.getSQLSession();
            userList = sqlSession.getMapper(UserMapper.class).getAddressListByUserId(userId);
        } catch (Exception e) {
            // TODO: handle exception
            e.printStackTrace();
        } finally {
            MyBatisUtils.closeSqlSession(sqlSession);
        }
        for (User user : userList) {
            logger.debug("userCode:" + user.getUserCode() + "\tuserName:" + user.getUserName());
            //遍歷到address的值的時候,因為它是個集合,所以再巢狀一個迴圈
            for (Address address : user.getAddressList()) {
                logger.debug("address---->" + address.getId()
                        + "\tcontact:" + address.getContact()
                        + "\taddressDesc:" + address.getAddressDesc()
                );
            }
        }
    }

測試的結果沒有問題:
在這裡插入圖片描述

Mybatis框架的使用之五傳送門:
https://blog.csdn.net/wangduanqs/article/details/85063368