您的位置:首页 > 其它

Mybatis---一对一关联表查询

2016-02-25 14:20 465 查看
开发过程中表的关联查询几乎处处可见,Mybatis对关联查询可进行很好的处理,下面主要记录下一对一关联表的查询。

此处用到两个实体类及其关系如下:



School与President为一对一关联,设计javaBean:

//校长
public class President {
private int id;
private String name;

@Override
public String toString() {
return "President [id=" + id + ", name=" + name + "]";
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}


public class School {
private int id;
private String name;
private President president;
@Override
public String toString() {
return "School [id=" + id + ", name=" + name + ", president=" + president + "]";
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public President getPresident() {
return president;
}
public void setPresident(President president) {
this.president = president;
}
}
创建数据表:

create table president1(
p_id int not null auto_increment primary key,
p_name varchar(50) not null
);
insert into president1(p_name) values('lily'),('Tom');

create table school1(
s_id int not null auto_increment primary key,
s_name varchar(50) not null,
president_id int not null,
constraint foreign key(president_id) references president1(p_id)
);
insert into school1(s_name,president_id) values('上海大学',1),('复旦大学',2);


我们若想根据School的id查询scool的包含president的信息有两种方法:

Method1:关联查询

在sql中可通过如下的sql语句查询:

select * from president1 p,school1 s where p.p_id=s.president_id and s.s_id=1;
查询结果:



mybatis中第一种解决方法就是基于这种直接关联查询的思想:先把结果查询,然后利用ResultMap映射进行JavaBean的生成

此方法对应的mapper配置:

<!-- 根据id获得包含校长信息的学校信息 -->
<select id="getSchool1" resultMap="getSchool1Map">
select * from president1 p,school1 s where p.p_id=s.president_id and s.s_id=#{#}
</select>

<resultMap type="School" id="getSchool1Map">
<id column="s_id" property="id"/>
<result column="s_name" property="name"/>
<association property="president" javaType="President">
<id column="p_id" property="id"/>
<result column="p_name" property="name"/>
</association>
</resultMap><!-- 根据id获得包含校长信息的学校信息 -->
<select id="getSchool1" resultMap="getSchool1Map">
select * from president1 p,school1 s where p.p_id=s.president_id and s.s_id=#{id}
</select>

<resultMap type="School" id="getSchool1Map">
<id column="s_id" property="id"/>
<result column="s_name" property="name"/>
<association property="president" javaType="President">
<id column="p_id" property="id"/>
<result column="p_name" property="name"/>
</association>
</resultMap>
看上去与单表查询没什么不同?那就错了,需要注意到association标签,mybatis官方文档对该标签的解释为:一个复杂的类型关联;许多结果将包成这种类型。也就是说我们可以通过它把查询结果中的部分结果包装成一个javabean,上面的配置我们把(p_id,p_name)封装如President中,看一下此时的测试结果:



貌似很完美的解决了问题,实际上对于一般的情况这种方法是适用的。

     下面提一种非同一般的情况,如果两个关联表中含有字段名相同的字段咋办?比如如果president1和school1中p_name 和s_name都改成name,为了模拟这种情况,也懒得再建新的数据表,我们通过查询结果起别名的方法,mapper配置:

<!-- 根据id获得包含校长信息的学校信息 -->
<select id="getSchool2" resultMap="getSchool2Map">
select s_id,s_name name,p_id,p_name name from president1 p,school1 s where p.p_id=s.president_id and s.s_id=#{id}
</select>

<resultMap type="School" id="getSchool2Map">
<id column="s_id" property="id"/>
<result column="name" property="name"/>
<association property="president" javaType="President">
<id column="p_id" property="id"/>
<result column="name" property="name"/>
</association>
</resultMap>
java测试代码:

public void testGetSchoolById2(){
SqlSessionFactory sessionFactory = DbUtils.getSqlFactory();
SqlSession session = sessionFactory.openSession();
String statement = "com.cjc.mapper.schoolMapper.";
School s1 = session.selectOne(statement+"getSchool2", 1);
System.out.println(s1);
session.close();
}
可以猜测下测试的结果,无非有下面几种:

运行时异常
放回null值
返回结果,输出:School [id=1, name=上海大学, president=President [id=1, name=lily]]
返回结果,输出:School [id=1, name=上海大学, president=President [id=1, name=上海大学]]

实际的测试结果如下:



mybatis很诡异的把president的name信息搞成了school的name,因为在resultmap中有两个相同的映射关系school自身的name映射和president的name映射,针对sql查询结果,测试表明,如果查询结果中有多个name,即使它们的值不同,mybatis只会将第一个name的值取出注入到映射关系对应的实体类属性中。

难道就没有方法解决这种情况?当然有,这时就要引出第二种关联查询方法。

Method2:嵌套查询

我们可以通过下面的方法进行人工拼接要查询的结果,比如要查询id为1的school信息,首先我们先只查询学校的信息:



然后根据查询的学校信息中的president_id去president1表中查询president的信息:

最后我们自己根据两次查询的结果手动拼接成最终结果即可。

mybatis嵌套查询的思想与上面讲的思想类似,先看一下该方法的mapper配置:

<select id="getSchool3" resultMap="getSchool3Map">
<span style="white-space:pre">	</span>select * from school1 where s_id=#{id}
</select>
<resultMap type="School" id="getSchool3Map">
<span style="white-space:pre">	</span><id column="s_id" property="id"/>
<span style="white-space:pre">	</span><result column="s_name" property="name"/>
<span style="white-space:pre">	</span><!-- 此处不是使用resultMap的形式,而是将getPresident查询的结果嵌入进来,
<span style="white-space:pre">	</span>column="president_id"的使用是为了将该school中的president_id信息传入查询:getPresident中-->
<span style="white-space:pre">	</span><association property="president" column="president_id" select="getPresident" />
</resultMap>
<!-- 根据p_id查询president的信息 -->
<select id="getPresident" resultType="President">
<span style="white-space:pre">	</span>select p_id id,p_name name from president1 where p_id=#{id}
</select>
此过程相当于执行了两次查询,因为在每次查询为都对结果进行了封装,所以即使两个表有相同的字段名,最后的实体类的结果信息也不会有method1中的情况,查询结果:

这次真的完美的解决了关联表查询的情况


测试源码下载
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息