mybatis resultMap结果映射集用法详解
resultmap是mybatis中最复杂的元素之一,它描述如何从结果集中加载对象,主要作用是定义映射规则、级联更新、定制类型转化器。
resultmap元素构成:
元素 | 子元素 | 作用 |
---|---|---|
constructor | idArg、arg | 用于配置构造器方法 |
id | 将结果集标记为id,以方便全局调用 | |
result | 配置pojo到数据库列名映射关系 | |
association | 级联使用 | 代表一对一关系 |
collection | 级联使用 | 代表一对多关系 |
discriminator | 级联使用 | 鉴别器,根据实际选择实例,可以通过特定条件确定结果集。 |
1、id和result元素
创建实体类User:
class User{
private int userId;
private String name;
public User(long userId,String name){
this.userId = userId;
this.name = name;
}
}
id、result是最简单的映射,id为主键映射;result为其他基本数据库表字段到实体类属性的映射。此时resultmap的xml如下:
<resultMap type="User" id="userMap">
<id property="UserId" column="user_id" javaType="int" jdbcType="int"/>
<result property="name" column="name" javaType="String" jdbcType="VARCHAR"/>
</resultMap>
id、result语句属性配置细节:
属性 | 描述 |
---|---|
property | 需要映射到javabean的属性名称。 |
column | 数据表的列名或者标签别名。 |
javaType | 一个完整的类名,或者是要给类型别名。如果你匹配的是一个JavaBean,那么MyBatis通常会自行检测到。然后,如果你是要映射到一个HashMap,那么需要指定javaType要达到的目的。 |
jdbcType | 数据表支持的类型列表。这个属性只在insert、update、或delete的时候针对允许为空的列有用。jdbc需要这项,但mybaits不需要。如果是针对jdbc编码,且允许有空的列,需要指定这项。 |
typeHandler | 使用这个属性可以覆写类型处理器。这项值可以是一个完整的类名,也可以是一个类型别名。 |
2、constructor构造器
在resultMap中,通常使用id、result子元素把java实体类的属性映射到数据库表的字段上。但是如果在遇到javabean没有无参构造函数时,还需要使用构造器元素实现一个javabean的实例化和数据注入。以实体类User为例,那么对应的resultmap就需要添加构造器:
<constructor>
<idArg column="user_id" javaType="long"/>
<arg column="name" javaType="String"/>
</constructor>
定义Java实体类的属性映射到数据库表的字段上。我们也可以使用实体类的构造方法来实现值的映射,这是通过构造方法参数的书写的顺序来进行赋值的。
这样mybatis就知道需要用这个构造方法构造了。
3、结果集处理方法:
(1)使用map存储结果集:
一般情况下,所有select语句都可以使用map存储,但是map可读性较差,所以并不是推荐的方式。
<select id="findUserId" parameterType="long" resultType="map">
select user_id,name from user where user_id=#{userId}
</select>
(2)使用pojo存储结果集:
一般我们都使用pojo储存查询结果。我么可以使用select自动映射,还可以使用select语句中的resultMap属性配置映射集合,不过需要提前定义resultMap。
<select id="findUserId" parameterType="long" resultMap="userMap">
select suer_id,name from user where user_id = #{userId}
</select>
4、级联:
在数据库中包含着一对多、一对一的关系。比如说一个人和他的身份证就是一对一的关系,但是他和他的银行卡就是一对多的关系。我们的生活中存在着很多这样的场景。我们也希望在获取这个人的信息的同时也可以把他的身份证信息一同查出,这样的情况我们就要使用级联。在级联中存在三种对应关系。
- 一对一的关系。
- 一对多的关系。
- 多对多的关系。
1、association一对一级联:
继续使用user类,同时为其增加一个Card类,人和他的身份证成了一对一的关系。在创建一个Card类。
@Data
@Alias("card")
//@Alias注解:添加别名
public class Card{
private Long id;
private Long userId;
private String name;
private String address;
}
这时需要在User中添加属性Card,这样就形成了一对一的级联。
@Data
@Alias("user")
public class User{
private Long id;
private String username;
private String password;
private String email;
private Card card;
}
这时需要CardMapper提供findCardByUserId(Long userId)方法,定义其映射器如下:
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.changzhen.mybatis.mapper.CardMapper">
<resultMap id="cardMap" type="card">
<id property="id" column="id"></id>
<result property="userId" column="user_id"/>
<result property="name" column="name"/>
<result property="address" column="address"/>
</resultMap>
<select id="findCardByUserId" parameterType="long" resultMap="cardMap">
SELECT id, user_id, name, address FROM card WHERE user_id = #{userId}
</select>
</mapper>
有了CardMapper,就可以在UserMapper中使用findCardByUserId进行级联:
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.changzhen.mybatis.mapper.UserMapper">
<select id="getUser" resultMap="userMap" parameterType="long">
SELECT id,username,password,email FROM USER WHERE id=#{id}
</select>
<resultMap id="userMap" type="user">
<id property="id" column="id"/>
<result property="password" column="password"/>
<result property="email" column="email"/>
<association property="card" column="id" select="com.changzhen.mybatis.mapper.CardMapper.findCardByUserId"/>
</resultMap>
级联查询是根据返回的id进行级联查询,所以在getUser的时候,一定要将数据库的id获取到。
通过关联处理,其中select元素指定的sql查询,而column则是指定传递给select的参数,是user对象id。当取出User的时候,mybatis就知道下面的sql取出我们需要的级联信息:
<association property="card" column="id" select="com.changzhen.mybatis.mapper.CardMapper.findCardByUserId"/>
其中参数是User的值,通过column配置,如果是多个参数则使用逗号隔开。
执行程序,可以看出两条sql语句分别查询了User和Card。
2、collection一对多级联
一对多的级联,一个身份证可以办理多张银行卡。每个用户对应一个身份证,每个身份证对应多个银行卡。所以这两个级联,分别使用association和collection完成。
首先,创建BankCard类,为Card增加bankCardList属性:
@Alias("bankCard")
@Data
public class BankCard{
private Long id;
private Long userId;
private String bankName;
private int type;
}
@Data
@Alias("card")
public class Card {
private Long id;
private Long userId;
private String name;
private String address;
private List<BankCard> bankCards;
}
创建BankCardMapper:
@Mapper
public interface BankCardMapper{
public List findCreditCardsByUserId(Long userId);
}
xml最简单的映射器:
<mapper namespace="com.changzhen.mybatis.mapper.CreditCardMapper">
<select id="findCreditCardsByUserId" parameterType="long" resultType="creditCard">
SELECT id, user_id, bank_name, type FROM bank_card WHERE user_id = #{userId}
</select>
</mapper>
最后在Card映射器中添加collection,一对多级联:
<mapper namespace="com.changzhen.mybatis.mapper.CardMapper">
<resultMap id="cardMap" type="card">
<id property="id" column="id"></id>
<result property="userId" column="user_id"/>
<result property="name" column="name"/>
<result property="address" column="address"/>
<collection property="creditCards" column="id" select="com.changzhen.mybatis.mapper.BankCardMapper.findBankCardsByUserId"/>
</resultMap>
<select id="findCardByUserId" parameterType="long" resultMap="cardMap">
SELECT id, user_id, name, address FROM card WHERE user_id = #{userId}
</select>
</mapper>
这次共执行了三条sql语句:
3、discriminator鉴别器级联:
鉴别器级联是在不同情况下使用不同的pojo。例如,在本例中我们每个人都有好多银行卡,但是银行卡的种类却不相同,比如有借记卡(DebitCard)和信用卡(CreditCard),我们需要按需来创建不同的pojo。这时我们就需要在BankCard中添加types属性进行判断,确定使用哪个pojo。
接下来需要创建DebitCard和CreditCard两个继承BankCard的子类:
@Data
public class CreditCard extends BankCard {
/**
* 消费额度
*/
private String creditLine;
}
@Data
public class DebitCard extends BankCard {
/**
* 存款金额
*/
private String deposit;
}
通过BankCard中types的属性判断使用那种银行卡,例如types等于1为借记卡,等于2为信用卡。接下来需要修改bankCard.xml,添加discriminator鉴别器,他相当于java中的switch语句。
bankCard.xml修改为如下:
<mapper namespace="com.changzhen.mybatis.mapper.BankCardMapper">
<resultMap id="bankCardMapper" type="bankCard">
<id property="id" column="id"/>
<result property="userId" column="user_id"/>
<result property="bankName" column="bank_name"/>
<result property="types" column="types"/>
<discriminator javaType="int" column="types">
<case value="1" resultMap="debitCardMapper"></case>
<case value="2" resultMap="creditCardMapper"></case>
</discriminator>
</resultMap>
<select id="findBankCardsByUserId" parameterType="long" resultMap="bankCardMapper">
SELECT id, user_id, bank_name, types FROM bank_card WHERE user_id = #{userId}
</select>
<resultMap id="debitCardMapper" type="debitCard" extends="bankCardMapper"/>
<resultMap id="creditCardMapper" type="creditCard" extends="bankCardMapper"/>
</mapper>
其中:
<discriminator javaType="int" column="types">
<case value="1" resultMap="debitCardMapper"></case>
<case value="2" resultMap="creditCardMapper"></case>
</discriminator>
首先定义了discriminator,它对应的column为types,Java类型为int。case配置了不同的resultmap,如value=1时,引入debitCardMapper,value=2时,引入creditCardMapper,它们都扩展了bankCardMapper。
就像继承关系一样,resultmap也可以继承,加入自己的属性。借记卡添加deposit属性,信用卡添加creditLine属性。
可以看出,返回的数据已经根据types使用了不同的pojo。
还没有评论,来说两句吧...