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

猜你喜欢

转载自blog.csdn.net/wangduanqs/article/details/85023293