关联查询
一对一映射
先创建第二张表personidcard和其实体类,然后再给表person添加外码:
alter table person add constraint fk_person_idcard_cardid foreign key (cardid) references personidcard(cardid);
我们需要根据传入的id值来查询一个人的全部信息(person表和personidcard表),sql语句是:
select p.*,c.*
from person p inner join personidcard c on p.cardid =c.cardid
where p.id=#{id}
但是返回值现在不好处理了,因为这涉及到了两个类中的属性。MyBatis有业务拓展类和resultMap类两种实现方式。
业务拓展类
需要新建一个业务拓展类,使其继承成员变量多的类(person),然后直接代码创建变量少的类的属性:
public class PersonBussiness extends Person{
private int cardid;
private String cardinfo;
public int getCardid() {
return cardid;
}
public void setCardid(int cardid) {
this.cardid = cardid;
}
public String getCardinfo() {
return cardinfo;
}
public void setCardinfo(String cardinfo) {
this.cardinfo = cardinfo;
}
@Override
public String toString() {
return super.toString()+", "+this.cardid+", "+this.cardinfo;
}
}
这样就可以在resultType中写入返回值类型是PersonBussiness了:
<select id="queryStudentWithBussiness" parameterType="int" resultType="personbussiness">
select p.*,c.*
from person p inner join personidcard c on p.cardid =c.cardid
where p.id=#{id}
</select>
用业务拓展类的核心是用resultType指定类的属性包含多表查询的所有字段。但是这个方法有些弊端,如果有很多张表都有关联,业务拓展类实现起来就很麻烦了。
ResultMap
之前已经多次出现这个resultMap了,给人的感觉是,实现简单的东西比较繁杂,但是可以去做一些特定的任务,给人一种吃力不讨好的感觉。果不其然用resultMap来实现关联查询就十分的方便。
在数据库中通过外键将两个表关联起来,那么在java中将两个类关联起来可以通过将一个类作为另外一个类的成员变量来实现(在person类中增加成员PersonIdCard)。
将PersonIdCard类关联到person类中之后resultMap的返回值就可以直接写Person了:
<select id="queryStudentWithHashMapForFk" parameterType="int" resultMap="person_idCard_map">
select p.*,c.*
from person p inner join personidcard c on p.cardid =c.cardid
where p.id=#{id}
</select>
<resultMap id="person_idCard_map" type="Person">
<id property="id" column="id"/>
<result property="name" column="name"/>
<result property="age" column="age"/>
<!-- 对象成员时,如果是一对一映射,就用association;javaType指定改属性的类型-->
<association property="personIdCard" javaType="PersonIdCard">
<id property="cardid" column="cardid"/>
<result property="cardinfo" column="cardinfo"/>
</association>
</resultMap>
resultMap中的id和result字段和之前的处理方式一样,现在主要针对于对象类型,即关联的personidcard类的处理。如果是一对一映射就用association标签;如果是一对多就是collection标签。在association标签中还需要加上这个成员变量的名称property和类型javaType。
这个关联类中也有自己的成员变量,其本身也对应了一张表,所以也要写上自身的变量,同样是用id和result。
一对多映射
新建另一张表personClass和其实体类,给person添加外码class。然后说一个题外话:Mysql不允许同时更新(删除)和查询同一张表,是我在尝试以多此一举的方式更新表的时候发现的这个问题。
由于还是用ResultMap来实现,所以要将personClass和person这两个类关联起来。现在是一对多的联系,只能在personClass类中增加person的list。
在resultMap中,其它的写法全都一样,唯一不同的是,现在关联的类是一对多关联,要写collection(一对一写association),并且描述类型的时候不能再用javatype了(因为javaType不用写list,而单写一个person不能正确表示personClass当中的成员的类型,也不能体现其是一对多关联),而是特有的ofType,然后ofType里面写person,表明这个集合的元素类型是person:
<select id="queryClassAndPersons" parameterType="int" resultMap="class_person_map"> select c.*,p.* from person p inner join personclass c on c.classid=p.class where p.class=#{class} </select> <resultMap id="class_person_map" type="personclass"> <id property="classid" column="classid"/> <result property="classname" column="classname"/> <!-- 描述属性类型javaType 描述属性的元素类型是oftype--> <collection property="persons" ofType="person"> <id property="id" column="id"/> <result property="name" column="name"/> <result property="age" column="age"/> </collection> </resultMap>
然后collection标签内依旧要配置person的成员属性。