您的位置:首页 > 其它

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

2018-12-16 01:47 281 查看

绝大多数情况下,一条完整的信息至少分别来自两张或以上的表,连表查询非常常见,这种情况下可以使用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.
24000
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://www.geek-share.com/detail/2756109810.html

阅读更多
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: