ResutMap
resultType 可以把查询结果封装到pojo类型中,但必须 pojo 类的属性名和查询到的数据库表的字段名一致。
如果 sql 查询到的字段与 pojo 的属性名不一致,则需要使用 resultMap 将字段名和属性名对应起来,进行手动配置封装,将结果映射到 pojo 中, resultMap 是 Mybatis 最强大的元素,它可以将查询到的复杂数据(比如查询到几个表中数据)映射到一个结果集当中。
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>
一、基本使用
· 假设我们数据库有一张用户表(user),有如下字段
_id int32
username varchar(25)
password varchar(25)
· 那么该表(User)对应的实体类
public class User{
Integer id;
String username;
String password;
getter and setter........
}
//1. 实体类中属性名尽量和数据表中的列名有点联系,不是必须,只是为了避免自己搞混了。
//2. 实体类必须要有无参构造函数,如果你添加了带参数的构造函数的话。
比如我们要查询指定id的用户信息,可以通过下面的sql语句
<select id="queryUserById" parameterType="java.lang.Integer" resultMap="UserResultMap">
select * from user where _id = #{id, jdbcType=INTEGER};
</select>
然后查询的结果通过resultMap映射到实体类返回
<!-- resultMap最终还是要将结果映射到pojo上,type就是指定映射到哪一个pojo -->
<!-- id:设置ResultMap的id -->
<resultMap type="User" id="UserResultMap">
<!-- <id />标签 定义主键 ,非常重要。
property:主键在pojo中的属性名
column:主键在数据库中的列名
jdbcType: 字段类型-->
<id property="id" column="_id" jdbcType="VARCHAR"/>
<!-- <result />标签 定义普通属性
property:pojo中的属性名
column:数据库中的列名
jdbcType: 字段类型-->
<result property="username" column="username" />
<result property="password" column="password" />
</resultMap>
resultMap 的 type 属性指向映射的实体类,注意:这里是使用了别名后的写法,如果没有在配置文件中配置别名,会报找不到类的的错误。没有配置的时候需要写完全的路径名称。比如:type=“com.demo.pojo.User” 。属性 id 是唯一的,方便调用。
对应的接口方法为
User queryUserById(Integer id);
这就是一个简单的使用。
二、一对一
假设我们需要查询用户的时候顺便把用户家庭住址也查询出来。
在数据库中用户表(user)的字段如下,
_id INT32
username varchar(25)
password varchar(25)
address_id int32 //加多一个地址表的主键映射
地址表(address)
_id INT32
address_name varchar(255)
remark varchar(255)
对应 User 表的实体类,在用户类中添加 Address 属性, Address 属性是一个引用类型,用于存储关联查询的地址信息,因为关联关系是一对一,所以只需要添加单个属性即可 。
public class User{
Integer id;
String username;
String password;
Address address; //
getter and setter........
}
Address 表的实体类
public class Address{
Integer id;
String address_name;
String remark ;
getter and setter ....
}
查询的sql语句如下:
<select id="queryUserById" parameterType="java.lang.Integer" resultMap="UserAddressResultMap">
select u._id uid,u.username,u.password,a._id aid,a.address_name,a.remark
from user u,address a
where u.address_id =a._id
and u._id =#{id, jdbcType=INTEGER};
</select>
对应的的Dao接口
public interface UserDao{
User queryUserById(Integer id);
}
配置ResultMap,使用 association 映射关联对象Address
<resultMap type="com.demo.pojo.User" id="UserAddressResultMap">
<id property="id" column="uid" jdbcType="VARCHAR"/>
<result property="username" column="username" />
<result property="password" column="password" />
<!-- association :配置一对一属性
property:User里面的address属性名
javaType:属性类型 -->
<association property="address" javaType="com.demo.pojo.Address">
<!-- <id/>:声明主键,表示aid是关联查询对象的唯一标识,-->
<id property="id" column="aid" />
<result property="address_name" column="address_name" />
<result property="remark " column="remark " />
</association>
</resultMap>
也可以在 association 上使用ResultMap来进行重用,提高代码可读性。比如这样:
............................
<association property="address" resultMap="AddressResult">
</association>
..................................
<resultMap type="com.demo.pojo.Address" id="AddressResult">
<id property="id" column="aid" />
<result property="address_name" column="address_name" />
<result property="remark " column="remark " />
</resultMap>
............................
上面中使用了 association 这个元素,定义关联对象的封装规则 ,实现关联属性的查询,使用 association 定义关联的单个对象的封装结果。如果你关联的不只是一个对象,那你可以添加多个 associaton 来关联 。
association 有两种使用形式,上面使用的是 嵌套结果,还有一种是 嵌套查询 的。还是上面的例子,修改一下
<resultMap type="com.demo.pojo.User" id="UserAddressResultMap">
<id property="id" column="uid" jdbcType="VARCHAR"/>
<result property="username" column="username" />
<result property="password" column="password" />
<!-- association定义关联对象的封装规则
select:表明当前属性是调用select指定的方法查询出结果,这里调用了同一包下的AddressMaper.xml中的查询方法
column:指定将那一列的值传递给这个方法
整个流程:使用Select指定的方法(传入column指定的这列参数的值)查出对象,并封装给property指定的属性
-->
<association property="address" select="com.demo.mapper.AddressMapper.queryAddressById" column="address_id ">
</association>
</resultMap>
<!-- 查询语句 -->
<select id="queryUserById" parameterType="java.lang.Integer" resultMap="UserAddressResultMap">
select * from user
where _id =#{id, jdbcType=INTETER};
</select>
上面调用了 AddressMapper.xml下面的 queryAddressById ,
<select id="queryAddressById" parameterType="java.lang.Integer" resultType="com.demo.pojo.Address">
select * from address
where _id =#{id, jdbcType=INTEGER};
</select>
最后调用 Dao接口的
User queryUserById(Integer id);
在查询完User表数据后,拿着查询到的 address_id 再去查询Address表数据。分多条SQL执行。这种方式是使用一条单独的select语句来加载关联的实体(在本例中就是Address实体),然后在association元素中引用此select语句。
三、一对多
一对一中使用的是 association,一对多中使用的则是 collection,用法和 association 大同小异,不过与一个是单一对象,一个是对象的集合。
比如,每一个用户都有多个邮箱,那么添加一个邮箱表(email),有如下字段
_id INT32
email VARCHAR(100)
在用户表(user)中添加 email_id 字段
_id INT32
username varchar(25)
password varchar(25)
address_id int32 //地址表的主键映射
email_id int32 //邮箱表的主键映射
用户表实体类添加 email 集合
public class User{
Integer id;
String username;
String password;
Address address; //
List<Email>emails;//存放email
getter and setter........
}
email 的实体类(Email)
public class Email{
Integer id;
String email;
.....
getter and setter ...
}
查询语句:
<select id="queryUserById" parameterType="java.lang.Integer" resultMap="UserEmailResultMap">
select u._id uid,u.username,u.password,e._id eid,e.email
from user u
left jion email e
on u.email_id =e._id
where u._id =#{id, jdbcType=INTEGER};
</select>
ResultMap配置
<resultMap type="com.demo.pojo.User" id="UserEmailResultMap">
<id property="id" column="uid" jdbcType="VARCHAR"/>
<result property="username" column="username" />
<result property="password" column="password" />
<!-- collection :配置一对多属性
property:User里面的对象集合属性名 emails
javaType:属性类型 这里可以省略不写的
ofType: 用来区分 JavaBean 属性类型和集合包含的类型,也就是填集合里面对象的类型
-->
<collection property="emails" javaType="java.util.ArrayList" ofType ="com.demo.pojo.Email">
<!-- <id/>:声明主键,表示aid是关联查询对象的唯一标识,-->
<id property="id" column="eid" />
<result property="email" column="email" />
</collection >
</resultMap>
你也可以在 collection 上使用ResultMap
<collection property="emails" javaType="java.util.ArrayList" ofType ="com.demo.pojo.Email" resultMap="EmailResultMap">
</collection>
<resultMap type="com.demo.pojo.Email" id="EmailResultMap">
<id property="id" column="eid" jdbcType="INTETER"/>
<result property="username" column="username" jdbcType="VARCHAR" />
</resultMap >
这里是嵌套结果的使用方式,如果是嵌套查询的方式,collection 使用格式如下:
<collection column="传递给嵌套查询语句的字段参数" property="pojo对象中集合属性"
ofType="集合属性中的pojo对象" select="嵌套的查询语句" >
</collection>
嵌套查询的查询语句如下:
<select id="queryUserById" parameterType="java.lang.Integer" resultMap="UserEmailResultMap">
select * from user
where _id =#{id, jdbcType=INTEGER};
</select>
映射的ResultMap为:
<resultMap type="com.demo.pojo.User" id="UserEmailResultMap">
<id property="id" column="_id" jdbcType="VARCHAR"/>
<result property="username" column="username" />
<result property="password" column="password" />
<!-- column:user表中email 的主键 -->
<collection column="email_id" property="emails" javaType="java.util.ArrayList"
ofType ="com.demo.pojo.Email" select="com.demo.mapper.EmailMapper.queryEmailById">
</collection >
</resultMap>
collection 中的 select 调用 EmailMapper.xml的 queryEmailById 语句,如下:
<select id="queryEmailById" parameterType="java.lang.Integer" resultMap="EmailResultMap">
select * from email
where _id =#{id, jdbcType=INTEGER};
</select>
<--结果集映射--->
<resultMap id="EmailResultMap" type="com.demo.pojo.Email">
<id column="_id" jdbcType="INTEGER" property="id" />
<result column="email" jdbcType="VARCHAR" property="email" />
</resultMap>
四、多对多
一个用户可以购买多种商品。一种商品可以多个用户购买。这是比较常见的场景。那么在数据库表上实现,需要在添加一个关系表(user_commodity),将用户表(user)和商品表(commodity)连接起来。
新建商品表 (commodity) ,有如下字段
_id INT32
name VARCHAR(255)
prices DECIMAL(5,2)
关系表 (user_commodity)
_id INT32
user_id INT32
commodity_id INT32
商品表实体类 (Commodity)
public class Commodity{
Integer id;
String name;
List<User>users;
getter and setter..
}
关系表实体类(UserCommodity)
public class UserCommodity{
Integer id;
Integer userId;
Integer commodityId;
getter and setter...
}
然后用户实体类(User)中添加
public class User{
..........
..........
List<Commodity>commoditise;//添加商品集合
}
那么,如果我要根据用户 id 查询该用户购买了多少种商品,查询语句如下:
<select id="queryCommodityByUserId" parameterType="java.lang.Integer" resultMap="UserCommodityResult">
select * from user
where _id =#{id, jdbcType=INTEGER};
</select>
配置ResultMap
<resultMap id="UserCommodityResult" type="com.demo.pojo.User">
<id property="id" column="_id" jdbcType="VARCHAR"/>
<result property="username" column="username" />
<result property="password" column="password" />
<!---这里使用 嵌套查询 方式--->
<association property="commoditise" javaType="com.demo.pojo.Commodity" column="uid" select="com.demo.mapper.CommodityMapper.queryCommodityById"/>
</resultMap>
在 CommodityMapper 中的 selectCommodity
<--- 根据用户id,在关系表( user_commodity )和商品表(commodity )中进行 连接查询 -->
<select id="queryCommodityById" parameterType="java.lang.Integer" resultMap="CommodityResult">
select c._id ,c.name from commodity c,user_commodity uc
where c._id =uc.commodity_id
and uc.user_id =#{id, jdbcType=INTEGER};
</select>
<resultMap id="CommodityResult" type="com.demo.pojo.Commodity">
<id property="id" column="_id" jdbcType="VARCHAR"/>
<result property="name" column="name" />
</resultMap>
在Dao的接口方法:
public inteface User{
User queryCommodityByUserId(Integer Id);
}
五、汇总
resultType:
作用:将查询结果按照sql列名pojo属性名一致性映射到pojo中。
场合:常见一些明细记录的展示,比如用户购买商品明细,将关联查询信息全部展示在页面时,此时可直接使用resultType将每一条记录映射到pojo中,在前端页面遍历list(list中是pojo)即可。
resultMap:
使用association和collection完成一对一和一对多高级映射(对结果有特殊的映射要求)。
association:
作用:将关联查询信息映射到一个pojo对象中。有多少个关联对象就添加多少个 association 元素。
collection:
作用:将关联查询信息映射到一个list集合中,有多少个关联对象就添加多少个 collection 元素。
当 pojo 对象的属性名称和数据库字段名不完全一样的时候,使用 resultType 无法将查询结果映射到 pojo 对象的 pojo 属性中,根据对结果集查询遍历的需要选择使用 resultType 还是 resultMap。
association 和 collection 可以相互嵌套或者自身嵌套使用,比如在 association 中 嵌套 collection :
<resultMap ......>
<association ..........>
...............................
<collection..........>
...............
</collection>
</association>
</resultMap>
或者 collection 嵌套 association
<resultMap ......>
<collection..........>
...............................
<association..........>
...............
</association>
</collection>
</resultMap>
一起使用:
<resultMap ......>
<association..........></association>
<collection..........>
...............................
<association..........></association>
...............
</collection>
</resultMap>
一般不建议超过3个表以上的连接嵌套查询,如果有,那么需要考虑下数据库表的重新设计了。