一对一查询
需求:
查询订单信息,关联查询创建订单的用户信息。
记住:用Mybatis开发的顺序就是
1.写sql语句
2.创建pojo类来完成映射
3.写Mapper.xml
4.写Mapper.java接口
---------------------------------------------------------------------------------------------------------------------------------------------------
我们知道Mybatis中mapper.xml中分为resultType和resultMap两种,这两种我们都讲:
一:先讲resultMap:
先给出案例结构:
cn.itcast.mybatis.po包下面的类(items,orderdetail,Orders,User)都是根据数据库的4张表创建的实体类。
1.我们先来分析一下怎么写sql语句:
写sql语句时要先根据需求确定查询的主表和查询的关联表:
根据“查询订单信息,关联查询创建订单的用户信息” 很明显,查询的主表是订单表,查询的关联是用户表。
关联查询使用内链接?还是外链接?由于orders表中有一个外键(user_id),通过外键关联查询用户表只能查询出一条记录,可以使用内链接。
sql如下:
SELECT
orders.*,
USER.username,
USER.sex,
USER.address
FROM
orders,
USER
WHERE orders.user_id = user.id
2.根据select(orders.*,USER.username,USER.sex,USER.address)语句 创建Pojo类
我们创建的pojo类要满足orders.*,USER.username,USER.sex,USER.address这些映射,很明显单纯依靠数据库的映射(Orders.java和User.java)不能满足,所以要新写一个类OrdersCustom.java。
如下:
package cn.itcast.mybatis.po;
import java.util.Date;
public class OrdersCustom extends Orders{
private String username;
private String sex;
private String address;
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public String getSex() {
return sex;
}
public void setSex(String sex) {
this.sex = sex;
}
public String getAddress() {
return address;
}
public void setAddress(String address) {
this.address = address;
}
}
为什么这个类要继承Orders而不是继承User.java因为根据orders.*,USER.username,USER.sex,USER.address,很明显,要映射的数据是order表中的全部数据以及user
表中的username,sex,address这些数据,直接继承Order类的话就可以少定义一些属性,只要定义username,sex,address。就可以了。
3.写Mapper.xml和Mapper.java接口(放在同一个包下面,用接口的方式去加载)
OrderMapperCustom.xml的代码如下:
<?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">
<!-- nanmespace:命名空间。 作用就是对sql进行分类话管理,理解Sal分离
注意:使用mapper代理方式,namespace有特殊重要的作用
-->
<mapper namespace="cn.itcast.mybatis.mapper.OrdersMapperCustom">
<select id="findOrdersUser" resultType="cn.itcast.mybatis.po.OrdersCustom">
SELECT ORDERS.* ,
user.`username`,
user.`sex`,
user.`address`
FROM orderS,USER
WHERE ORDERS.`user_id`=USER.`id`
</select>
</mapper>
OrdersMapperCustom.java代码如下:
package cn.itcast.mybatis.mapper;
import java.util.List;
import cn.itcast.mybatis.po.OrdersCustom;
public interface OrdersMapperCustom {
public List<OrdersCustom> findOrdersUser();
}
同时不要忘了在SqlMapConfig.xml。
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE configuration
PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration>
<!-- properties的配置必须写在typeAliases的上面 -->
<properties resource="db.properties"></properties>
<!-- 和spring整合后 environments配置将废除-->
<environments default="development">
<environment id="development">
<!-- 使用jdbc事务管理-->
<transactionManager type="JDBC" />
<!-- 数据库连接池-->
<dataSource type="POOLED">
<property name="driver" value="${jdbc.driver}" />
<property name="url" value="${jdbc.url}" />
<property name="username" value="${jdbc.username}" />
<property name="password" value="${jdbc.password}" />
</dataSource>
</environment>
</environments>
<mappers>
<!-- 用mapper接口的方式加载-->
<!--
遵循一些规范:需要将mapper接口类名和mapper.xml映射文件名称保持一致
且在一个目录中。
当着这个规范的前提是:使用mapper代理方法。
-->
<mapper class="cn.itcast.mybatis.mapper.OrdersMapperCustom"/>
</mappers>
</configuration>
4.编写测试代码Mybatis_mappertest.java:
package cn.itcast.mybatis.test;
import java.io.IOException;
import java.io.InputStream;
import java.util.Date;
import java.util.List;
import org.apache.ibatis.io.Resources;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;
import org.junit.Before;
import org.junit.Test;
import cn.itcast.mybatis.mapper.OrdersMapperCustom;
import cn.itcast.mybatis.mapper.userMapper;
import cn.itcast.mybatis.po.User;
import cn.itcast.mybatis.po.UserCustom;
import cn.itcast.mybatis.po.UserQueryVo;
public class Mybatis_mappertest {
private SqlSessionFactory sqlSessionFactory;
@Before
public void setup() throws IOException
{ String resource="SqlMapConfig.xml";
InputStream inputStream= Resources.getResourceAsStream(resource);
//主要是生成SqlsessionFactory。
this.sqlSessionFactory=new SqlSessionFactoryBuilder().build(inputStream);
}
@Test
public void testMaper()
{
SqlSession sqlSession=null;
sqlSession=sqlSessionFactory.openSession();
//生成代理类
OrdersMapperCustom orderMapper=sqlSession.getMapper(OrdersMapperCustom.class);
orderMapper.findOrdersUser();
}
}
运行结果:一切正常。
二:再讲resultMap(重点):
resultMap映射的思想:
使用resultMap将查询结果中的订单信息映射到Orders对象中,在orders类中添加User属性,将关联查询出来的用户信息映射到orders对象中的user属性中。也就是说查出来的user信息都要映射在orders中新开的一个user属性中。
还是按照第一sql语句,第二pojo类,第三mapper.xml,mapper.java接口这种顺序来写。
1.sql语句:和之前的resulrType的sql语句一样:
SELECT
orders.*,
USER.username,
USER.sex,
USER.address
FROM
orders,
USER
WHERE orders.user_id = user.id
2.写pojo类:在原来的Orders.java中新增一个User属性:
User类:
package cn.itcast.mybatis.po;
import java.util.Date;
//对应数据库中的user表
public class User {
private int id;//对应数据库中主键
private String username;//对应数据库中用户的名称
private Date birthday;//对应数据库中的生日
private String sex;//性别
private String address;//地址
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public Date getBirthday() {
return birthday;
}
public void setBirthday(Date birthday) {
this.birthday = birthday;
}
public String getSex() {
return sex;
}
public void setSex(String sex) {
this.sex = sex;
}
public String getAddress() {
return address;
}
public void setAddress(String address) {
this.address = address;
}
}
Orders.java类:
package cn.itcast.mybatis.po;
import java.util.Date;
public class Orders {
private Integer id;
private Integer user_id;
private String number;
private Date createtime;
private String note;
//新增了一个User属性,为了保存查询得到的关联的User表的信息
private User user;
public User getUser() {
return user;
}
public void setUser(User user) {
this.user = user;
}
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public Integer getUser_id() {
return user_id;
}
public void setUser_id(Integer user_id) {
this.user_id = user_id;
}
public String getNumber() {
return number;
}
public void setNumber(String number) {
this.number = number;
}
public Date getCreatetime() {
return createtime;
}
public void setCreatetime(Date createtime) {
this.createtime = createtime;
}
public String getNote() {
return note;
}
public void setNote(String note) {
this.note = note;
}
}
3.写mapper.xml和mapper.java接口
OrdersMapperCustom.xml:
<?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">
<!-- nanmespace:命名空间。 作用就是对sql进行分类话管理,理解Sal分离
注意:使用mapper代理方式,namespace有特殊重要的作用
-->
<mapper namespace="cn.itcast.mybatis.mapper.OrdersMapperCustom">
<!-- 配置映射的订单信息 -->
<!-- id:指定查询列中的唯 一标识,订单信息的中的唯 一标识,如果有多个列组成唯一标识,配置多个id
就是说id要能唯一的标识出数据库中的Order表。
column:订单信息的唯 一标识 列
property:订单信息的唯 一标识 列所映射到Orders中哪个属性
-->
<resultMap type="cn.itcast.mybatis.po.Orders" id="OrdersUserResultMap">
<!-- 这一行的作用是要能唯一的识别出order表的,那么很明显是主键id -->
<id column="id" property="id"/>
<!-- 以下的几行result column就是表中的字段 property就是对应到相应pojo类中的属性-->
<result column="user_id" property="user_id"/>
<result column="number" property="number"/>
<result column="createtime" property="createtime"/>
<result column="note" property="note"/>
<!-- 配置映射的关联的用户信息 -->
<!-- association:用于映射关联查询单个对象的信息
property:要将关联查询的用户信息映射到Orders中哪个属性
-->
<!-- 下面的代码比较特殊,因为Order表是直接关联到user表,下面这么写的目的是把user表映射到Order类中
<association property="user"这里的user指的是orders类中的user,对应的是cn.itcast.mybatis.po.User
-->
<association property="user" javaType="cn.itcast.mybatis.po.User">
<!--
<id column="user_id" property="id"/>这里的是user_id指的是order表中只有这个属性能表示唯一的user表
-->
<id column="user_id" property="id"/>
<!-- 接下来的result property什么的都是为了把user表中的字段能匹配到
cn.itcast.mybatis.po.User这个类的属性中
-->
<result column="username" property="username"/>
<result column="sex" property="sex"/>
<result column="address" property="address"/>
</association>
</resultMap>
<select id="findOrdersUser" resultType="cn.itcast.mybatis.po.OrdersCustom">
SELECT ORDERS.* ,
user.`username`,
user.`sex`,
user.`address`
FROM orderS,USER
WHERE ORDERS.`user_id`=USER.`id`
</select>
<select id="findOrdersUseResultMap" resultMap="OrdersUserResultMap">
SELECT ORDERS.* ,
user.`username`,
user.`sex`,
user.`address`
FROM orderS,USER
WHERE ORDERS.`user_id`=USER.`id`
</select>
</mapper>
OrdersMapperCustom.java接口
package cn.itcast.mybatis.mapper;
import java.util.List;
import cn.itcast.mybatis.po.Orders;
import cn.itcast.mybatis.po.OrdersCustom;
public interface OrdersMapperCustom {
//这里的的函数名字要和OrdersMapperCustom.xml中的id一模一样
public List<OrdersCustom> findOrdersUser();
public List<Orders> findOrdersUseResultMap();
}
Junit测试代码:
package cn.itcast.mybatis.test;
import java.io.IOException;
import java.io.InputStream;
import java.util.Date;
import java.util.List;
import org.apache.ibatis.io.Resources;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;
import org.junit.Before;
import org.junit.Test;
import cn.itcast.mybatis.mapper.OrdersMapperCustom;
import cn.itcast.mybatis.mapper.userMapper;
import cn.itcast.mybatis.po.Orders;
import cn.itcast.mybatis.po.User;
import cn.itcast.mybatis.po.UserCustom;
import cn.itcast.mybatis.po.UserQueryVo;
public class Mybatis_mappertest {
private SqlSessionFactory sqlSessionFactory;
@Before
public void setup() throws IOException
{ String resource="SqlMapConfig.xml";
InputStream inputStream= Resources.getResourceAsStream(resource);
//主要是生成SqlsessionFactory。
this.sqlSessionFactory=new SqlSessionFactoryBuilder().build(inputStream);
}
@Test
public void testMaper()
{
SqlSession sqlSession=null;
sqlSession=sqlSessionFactory.openSession();
//生成代理类
OrdersMapperCustom orderMapper=sqlSession.getMapper(OrdersMapperCustom.class);
//创建包装对象,设置查询条件
//orderMapper.findOrdersUser();
@SuppressWarnings("unused")
List<Orders>list=orderMapper.findOrdersUseResultMap();
}
}
运行结果:一切正常。
resultType和resultMap实现一对一查询小结
实现一对一查询:
resultType:使用resultType实现较为简单,如果pojo中没有包括查询出来的列名,需要增加列名对应的属性,即可完成映射。
如果没有查询结果的特殊要求建议使用resultType。
resultMap:需要单独定义resultMap,实现有点麻烦,如果对查询结果有特殊的要求,使用resultMap可以完成将关联查询映射pojo的属性中。
resultMap可以实现延迟加载,resultType无法实现延迟加载。


浙公网安备 33010602011771号