java mybatis学习之表关联查询和延迟加载(懒加载)


表关联查询,说道表关联查询就要说道数据库。

数据库大致分两种,关系型数据库和非关系型数据库。

像我们一般用到的数据库Sql Server,MySQL,Oracle等等,这些都是关系型数据库。

这里有一个博客,就详细的写出来关系型数据库和非关系型数据库。http://blog.csdn.net/robinjwong/article/details/18502195/

关与数据库就不多说了。来说说我们的mybatis的表关联查询吧。

首先要进行项目开发,得先有数据库,我这次用的是oracle的数据库。

一般数据库表与表之间的关系分三种,分别为一对一,一对多,多对多。

其实呢,数据库的表与表之间的关系可以理解为1对多(N),N可以为1到∞。一般多对多的关系都会在良表中加个中间表,两表和中间表的关系分别为一对多,多对一。常见的多对多的关系有角色和权限,教师和学生等等。

1.数据库关系,一对多

就好比商品表和商品类型表,例如,五粮液和白酒,茅台和白酒。不同的商品,同一个类型。商品表和商品类型表就是多对一的关系。

在mybatis中查询表关联,代码如下

首先,是商品类型表的实体类

package com.jinglin.hotelsup.model;

import java.util.List;

public class GoodsType {
    private Integer goodstypeid;//商品ID
    private String goodstypename;//商品名称
    private String ifdel;//是否删除
    
    private List<GoodsInfo> goodsInfoList;
    
    public Integer getGoodsTypeId() {
        return goodstypeid;
    }
    public void setGoodsTypeId(Integer goodstypeid) {
        this.goodstypeid = goodstypeid;
    }
    public String getGoodsTypeName() {
        return goodstypename;
    }
    public void setGoodsTypeName(String goodstypename) {
        this.goodstypename = goodstypename;
    }
    public String getIfdel() {
        return ifdel;
    }
    public void setIfdel(String ifdel) {
        this.ifdel = ifdel;
    }
    public List<GoodsInfo> getGoodsInfoList() {
        return goodsInfoList;
    }
    public void setGoodsInfoList(List<GoodsInfo> goodsInfoList) {
        this.goodsInfoList = goodsInfoList;
    }
}
private List<GoodsInfo> goodsInfoList;
这里之所以用List是因为商品类型表跟商品表之间对应的关系是一对多

商品表的实体类
package com.jinglin.hotelsup.model;

public class GoodsInfo {
    private Integer goodsid;//商品ID
    private Integer companyid;//所属公司ID
    private Integer goodstypeid;//商品类型ID
    private Integer unitid;//库存ID
    private String createuser;//创建人
    private String updateuser;//修改人
    private String commdityid;//商品编号
    private String commdityname;//商品名称
    private String describeit;//详细描述
    private String createtime;//创建时间
    private String gooupdatetimedsid;//修改时间
    private String remark;//备注
    private String ifdelete;//是否删除
    
    //表关联,外键关联主键
    private GoodsType goodsType;
    
    public Integer getGoodsid() {
        return goodsid;
    }
    public void setGoodsid(Integer goodsid) {
        this.goodsid = goodsid;
    }
    public Integer getCompanyid() {
        return companyid;
    }
    public void setCompanyid(Integer companyid) {
        this.companyid = companyid;
    }
    public Integer getGoodstypeid() {
        return goodstypeid;
    }
    public void setGoodstypeid(Integer goodstypeid) {
        this.goodstypeid = goodstypeid;
    }
    public Integer getUnitid() {
        return unitid;
    }
    public void setUnitid(Integer unitid) {
        this.unitid = unitid;
    }
    public String getCreateuser() {
        return createuser;
    }
    public void setCreateuser(String createuser) {
        this.createuser = createuser;
    }
    public String getUpdateuser() {
        return updateuser;
    }
    public void setUpdateuser(String updateuser) {
        this.updateuser = updateuser;
    }
    public String getCommdityid() {
        return commdityid;
    }
    public void setCommdityid(String commdityid) {
        this.commdityid = commdityid;
    }
    public String getCommdityname() {
        return commdityname;
    }
    public void setCommdityname(String commdityname) {
        this.commdityname = commdityname;
    }
    public String getDescribeit() {
        return describeit;
    }
    public void setDescribeit(String describeit) {
        this.describeit = describeit;
    }
    public String getCreatetime() {
        return createtime;
    }
    public void setCreatetime(String createtime) {
        this.createtime = createtime;
    }
    public String getGooupdatetimedsid() {
        return gooupdatetimedsid;
    }
    public void setGooupdatetimedsid(String gooupdatetimedsid) {
        this.gooupdatetimedsid = gooupdatetimedsid;
    }
    public String getRemark() {
        return remark;
    }
    public void setRemark(String remark) {
        this.remark = remark;
    }
    public String getIfdelete() {
        return ifdelete;
    }
    public void setIfdelete(String ifdelete) {
        this.ifdelete = ifdelete;
    }
    public GoodsType getGoodstype() {
        return goodsType;
    }
    public void setGoodstype(GoodsType goodsType) {
        this.goodsType = goodsType;
    }
    
}
private GoodsType goodsType;此处商品表对应类型表是多对一

mybatis的配置
注释的代码是待会儿要说的延迟加载(懒加载)
<?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>
    <settings>
        <!-- 通过日志记录显示mybatis的执行过程 -->
        <setting name="logImpl" value="LOG4J"/>
        <!-- 延迟加载(懒加载),切记:以下两个都要 -->
        <!-- lazyLoadingEnabled设置为懒加载-->
        <setting name="lazyLoadingEnabled" value="true"/>
        <!-- aggressiveLazyLoading主动加载设置为false -->
        <setting name="aggressiveLazyLoading" value="false"/>
     </settings>
    <!-- 定义别名 -->
    <typeAliases>
        <typeAlias type="com.jinglin.hotelsup.model.GoodsInfo" alias="GoodsInfo"/>
        <typeAlias type="com.jinglin.hotelsup.model.GoodsType" alias="GoodsType"/>
    </typeAliases>
    <!-- 定义多个配置环境 -->
    <environments default="development">
        <!-- 定义其中一个配置环境 -->
        <environment id="development">
            <!-- 定义事务处理类型 -->
            <transactionManager type="JDBC"/>
            <!-- 定义数据源 -->
            <dataSource type="POOLED">
            <!-- 数据库驱动名称 -->
            <property name="driver" value="oracle.jdbc.driver.OracleDriver"/>
               <!-- 数据库URL地址 -->
               <property name="url" value="jdbc:oracle:thin:@localhost:1521:orcl"/>
               <!-- 数据账号 -->
               <property name="username" value="hotelmanager"/>
               <!-- 数据库密码 -->
               <property name="password" value="123456"/>
            </dataSource>
        </environment>
    </environments>
    
    <mappers>
    <mapper resource="com/jinglin/hotelsup/mapper/GoodsInfoMapper.xml"/>
    <mapper resource="com/jinglin/hotelsup/mapper/GoodsTypeMapper.xml"/>
    </mappers>
</configuration>

在这里,我用的依旧是昨天的开发方式。还是采用了mapper代理的方式开发

商品表的mapper

package com.jinglin.hotelsup.mapper;

import com.jinglin.hotelsup.dao.IDaoHotelsup;
import com.jinglin.hotelsup.model.GoodsInfo;

public interface GoodsInfoMapper extends IDaoHotelsup<GoodsInfo>{

}
<?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.jinglin.hotelsup.mapper.GoodsInfoMapper">
    <!-- 定义重复使用的代码段 -->
    <sql id="selectColumns">
        select gi.*,gt.goodstypename,gt.ifdel 
        from goodstype gt,goodsinfo gi 
        where gi.ifdelete='N'
        and gt.ifdel='N'
    </sql>
    <!-- 映射表关联返回结果集 -->
    <resultMap type="GoodsInfo" id="goodsInfoMap">
        <id column="goodsid" property="goodsid"/>
        <result column="companyid" property="companyid"/>
        <result column="goodstypeid" property="goodstypeid"/>
        <result column="unitid" property="unitid"/>
        <result column="createuser" property="createuser"/>
        <result column="updateuser" property="updateuser"/>
        <result column="commdityid" property="commdityid"/>
        <result column="commdityname" property="commdityname"/>
        <result column="describeit" property="describeit"/>
        <result column="createtime" property="createtime"/>
        <result column="gooupdatetimedsid" property="gooupdatetimedsid"/>
        <result column="remark" property="remark"/>
        <result column="ifdelete" property="ifdelete"/>
        <association property="goodsType" javaType="GoodsType">
            <id column="goodstypeid" property="goodstypeid"/>
            <result column="goodstypename" property="goodstypename"/>
            <result column="ifdel" property="ifdel"/>
        </association>
    </resultMap>
    <!-- 映射懒加载结果集 -->
    <!-- <resultMap type="GoodsInfo" id="goodsInfoLazyMap">
        <id column="goodsid" property="goodsid"/>
        <result column="companyid" property="companyid"/>
        <result column="goodstypeid" property="goodstypeid"/>
        <result column="unitid" property="unitid"/>
        <result column="createuser" property="createuser"/>
        <result column="updateuser" property="updateuser"/>
        <result column="commdityid" property="commdityid"/>
        <result column="commdityname" property="commdityname"/>
        <result column="describeit" property="describeit"/>
        <result column="createtime" property="createtime"/>
        <result column="gooupdatetimedsid" property="gooupdatetimedsid"/>
        <result column="remark" property="remark"/>
        <result column="ifdelete" property="ifdelete"/>
        <association property="goodsType" column="goodstypeid"
        select="com.jinglin.hotelsup.mapper.GoodsTypeMapper.getGoodsType">
        </association>
    </resultMap> -->
    <!-- 查询单条数据 -->
    <select id="selectById" parameterType="GoodsInfo" resultMap="goodsInfoMap">
        <include refid="selectColumns"></include>
        and gi.goodstypeid=gt.goodstypeid
        and gi.goodsid=#{goodsid}
    </select>
    <!-- 单表查询,商品表(懒加载) -->
    <!-- <select id="selectById" parameterType="GoodsInfo" resultMap="goodsInfoLazyMap">
        select * from goodsinfo
        where goodsid=#{goodsid}
    </select> -->
    <!-- 单表查询,查询商品表 (懒加载)-->                          <!-- 切记!!!此处parameterType的数据是从
    GoodsTypeMapper.xml文件中的懒加载结果集传过来的,此处不能用GoodsType和GoodsInfo类型,只能用传入的数据的类型Integer -->
    <!-- <select id="getGoodsType" resultType="GoodsInfo" parameterType="java.lang.Integer">
        select * from goodsinfo
        where goodstypeid=#{goodstypeid}
   </select> -->
</mapper>

商品类型表的mapper

package com.jinglin.hotelsup.mapper;

import com.jinglin.hotelsup.dao.IDaoHotelsup;
import com.jinglin.hotelsup.model.GoodsType;

public interface GoodsTypeMapper extends IDaoHotelsup<GoodsType>{

}
<?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.jinglin.hotelsup.mapper.GoodsTypeMapper">
    <!-- 定义重复使用的代码段 -->
    <sql id="selectColumns">
        select gi.*,gt.goodstypename,gt.ifdel 
        from goodstype gt,goodsinfo gi 
        where gi.ifdelete='N'
        and gt.ifdel='N'
    </sql>
    <!-- 映射返回结果集 -->
    <resultMap type="GoodsType" id="goodsTypeMap">
        <id column="goodstypeid" property="goodsTypeId"/>
        <result column="goodstypename" property="goodsTypeName"/>
        <result column="ifdel" property="ifdel"/>
         <collection resultMap="com.jinglin.hotelsup.mapper.GoodsInfoMapper.goodsInfoMap"
        column="goodstypeid" property="goodsInfoList"></collection>
    </resultMap>
    
    <!-- 映射懒加载的返回结果集 -->
    <!-- <resultMap type="GoodsType" id="goodsTypeLazyMap">
        <id column="goodstypeid" property="goodsTypeId"/>
        <result column="goodstypename" property="goodsTypeName"/>
        <result column="ifdel" property="ifdel"/>
         <collection select="com.jinglin.hotelsup.mapper.GoodsInfoMapper.getGoodsType"
        column="goodstypeid" property="goodsInfoList"></collection>
    </resultMap> -->
    
    <!-- 查询单条数据 -->
    <select id="selectById" parameterType="GoodsType" resultMap="goodsTypeMap">
        <include refid="selectColumns"></include>
        and gi.goodstypeid=gt.goodstypeid
        and gt.goodstypeid=#{goodstypeid}
    </select>
    
    <!-- 单表查询,查询单条数据(懒加载) -->
    <!-- <select id="selectById" parameterType="GoodsType" resultMap="goodsTypeLazyMap">
        select * from goodstype
        where goodstypeid=#{goodstypeid}
    </select> -->
    
    <!-- 单表查询,查询商品类型表(懒加载) -->
    <!-- <select id="getGoodsType" resultType="GoodsType" parameterType="GoodsType">
        select * from goodstype
        where goodstypeid=#{goodstypeid}
       </select> -->
</mapper>

商品表的查询测试

package com.jinglin.hotelsup.test;

import java.io.IOException;
import java.io.InputStream;

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.apache.log4j.Logger;
import org.junit.Test;

import com.jinglin.hotelsup.mapper.GoodsInfoMapper;
import com.jinglin.hotelsup.model.GoodsInfo;

public class TestGoodsInfo {
    //日志
    static Logger logger = Logger.getLogger(TestGoodsInfo.class);
    //创建工厂
    static SqlSessionFactory factory = null;
    //静态块
    static{
        InputStream inputStream = null;
        try {
            inputStream = Resources.getResourceAsStream("mybatis-config.xml");
        } catch (IOException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
            logger.error("创建连接对象出错,错误信息:"+e.getMessage());
        }
        factory = new SqlSessionFactoryBuilder().build(inputStream);
    }
    
    @Test
    public void test(){
        SqlSession session = factory.openSession();
        //mapper代理
        GoodsInfoMapper goodsInfoMapper = session.getMapper(GoodsInfoMapper.class);
        
        //根据id查询单条数据
        GoodsInfo goodsInfo = new GoodsInfo();
        goodsInfo.setGoodsid(2);
        GoodsInfo getGoodsInfo = goodsInfoMapper.selectById(goodsInfo);
        System.out.println(""+getGoodsInfo.getCommdityname());
        System.out.println(""+getGoodsInfo.getGoodstype().getGoodsTypeName());
    }
    
}

测试结果

商品类型表的查询测试

package com.jinglin.hotelsup.test;

import java.io.IOException;
import java.io.InputStream;
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.apache.log4j.Logger;
import org.junit.Test;

import com.jinglin.hotelsup.mapper.GoodsTypeMapper;
import com.jinglin.hotelsup.model.GoodsInfo;
import com.jinglin.hotelsup.model.GoodsType;

public class TestGoodsType {
    //日志
    static Logger logger = Logger.getLogger(TestGoodsInfo.class);
    //创建工厂
    static SqlSessionFactory factory = null;
    //静态块
    static{
        InputStream inputStream = null;
        try {
            inputStream = Resources.getResourceAsStream("mybatis-config.xml");
        } catch (IOException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
            logger.error("创建连接对象出错,错误信息:"+e.getMessage());
        }
        factory = new SqlSessionFactoryBuilder().build(inputStream);
    }
    
    @Test
    public void test(){
        SqlSession session = factory.openSession();
        //mapper代理
        GoodsTypeMapper goodsTypeMapper = session.getMapper(GoodsTypeMapper.class);
        
        //根据id查询单条数据
        GoodsType goodsType = new GoodsType();
        goodsType.setGoodsTypeId(2);
        GoodsType getGoodsType = goodsTypeMapper.selectById(goodsType);
        if(getGoodsType!=null){
            System.out.println("商品类型名称:"+getGoodsType.getGoodsTypeName());
            List<GoodsInfo> list = getGoodsType.getGoodsInfoList();
            if(list!=null){
                for (GoodsInfo goodsInfo : list) {
                    System.out.println("商品名称:"+goodsInfo.getCommdityname());
                }
            }
        }
    }
        
}

测试结果

这就是一个简单的表关联查询了。

接下来说说另一个跟表关联有关的。也就是mybatis的延迟加载,又称懒加载。

懒加载嘛,在你查询表的时候,当你需要进行表关联查询另一张表的时候才会执行查看另一张表的sql语句。也就是当你不需要显示另一张表的信息,那么你可以仅仅只查询一张表的数据。懒加载,是对sql语句的一种优化。联表查询虽然也能查询单张表的数据,但是会浪费很多资源,在表关联比较多,数据比较多的时候,查询数据的效率会大大降低。所以在这种时候,使用懒加载就是非常OK的了。

话不多说,直接上代码:

首先,懒加载需要导入jar包。名为cglib的jar包

<!-- mybatis懒加载需要引入的jar包,cglib包 -->
        <dependency>
              <groupId>cglib</groupId>
              <artifactId>cglib-nodep</artifactId>
              <version>3.1</version>
        </dependency>

这是我用maven自动加载的jar包

然后,在mybatis需要配置这样的一段代码

<settings>

      <!-- 延迟加载(懒加载),切记:以下两个都要 -->

        <!-- lazyLoadingEnabled设置为懒加载-->
        <setting name="lazyLoadingEnabled" value="true"/>
        <!-- aggressiveLazyLoading主动加载设置为false -->
        <setting name="aggressiveLazyLoading" value="false"/>
     </settings>

再然后就是mapper.xml文件的配置了

商品表的懒加载

resultMap元素的属性:

type:类的全限定名, 或者一个类型别名

id:当前命名空间中的一个唯一标识,用于标识一个result map.

  • association – 一个复杂的类型关联;许多结果将包成这种类型
    • 嵌入结果映射 – 结果映射自身的关联,或者参考一个
  • collection – 复杂类型的集
    • 嵌入结果映射 – 结果映射自身的集,或者参考一个

column:对应数据库的字段

property:对应实体类中的值

<!-- 映射懒加载结果集 -->
    <resultMap type="GoodsInfo" id="goodsInfoLazyMap">
        <id column="goodsid" property="goodsid"/>
        <result column="companyid" property="companyid"/>
        <result column="goodstypeid" property="goodstypeid"/>
        <result column="unitid" property="unitid"/>
        <result column="createuser" property="createuser"/>
        <result column="updateuser" property="updateuser"/>
        <result column="commdityid" property="commdityid"/>
        <result column="commdityname" property="commdityname"/>
        <result column="describeit" property="describeit"/>
        <result column="createtime" property="createtime"/>
        <result column="gooupdatetimedsid" property="gooupdatetimedsid"/>
        <result column="remark" property="remark"/>
        <result column="ifdelete" property="ifdelete"/>
        <association property="goodsType" column="goodstypeid"
        select="com.jinglin.hotelsup.mapper.GoodsTypeMapper.getGoodsType">
        </association>
    </resultMap>

<!-- 单表查询,商品表(懒加载) -->
    <select id="selectById" parameterType="GoodsInfo" resultMap="goodsInfoLazyMap">
        select * from goodsinfo
        where goodsid=#{goodsid}
    </select>
    <!-- 单表查询,查询商品表 (懒加载)-->                          <!-- 切记!!!此处parameterType的数据是从
    GoodsTypeMapper.xml文件中的懒加载结果集传过来的,此处不能用GoodsType和GoodsInfo类型,只能用传入的数据的类型Integer -->
    <select id="getGoodsType" resultType="GoodsInfo" parameterType="java.lang.Integer">
        select * from goodsinfo
        where goodstypeid=#{goodstypeid}
   </select>

商品类型的懒加载

<!-- 映射懒加载的返回结果集 -->
    <resultMap type="GoodsType" id="goodsTypeLazyMap">
        <id column="goodstypeid" property="goodsTypeId"/>
        <result column="goodstypename" property="goodsTypeName"/>
        <result column="ifdel" property="ifdel"/>
         <collection select="com.jinglin.hotelsup.mapper.GoodsInfoMapper.getGoodsType"
        column="goodstypeid" property="goodsInfoList"></collection>
    </resultMap>

<!-- 单表查询,查询单条数据(懒加载) -->
    <select id="selectById" parameterType="GoodsType" resultMap="goodsTypeLazyMap">
        select * from goodstype
        where goodstypeid=#{goodstypeid}
    </select>
    
    <!-- 单表查询,查询商品类型表(懒加载) -->
    <select id="getGoodsType" resultType="GoodsType" parameterType="java.lang.Integer"> 
   select
* from goodstype
   where goodstypeid
=#{goodstypeid}
   </select>

商品表的结果

可以看出,在控制台里面输出了两句查询单表的sql语句。

接下来,我将商品类型的查询注释掉

可以从控制台的日志信息里看出,我只进行了一次查询。但是却传了两个参数。是因为我这里只需要商品信息的内容,而不需要显示商品信息类型,懒加载就不会去加载我不需要的数据。也就不会去查询商品类型表。

所以说呢,懒加载就是当你在进行联表查询的时候,需要哪张表的数据它才会去对哪张表的数据进行查询,不需要的则不会去查询。

同样,不管是一对多或者是多对一的查询(一对一或多对多可以理解为特殊的一对多),都是可以使用懒加载的。

下面再来两张演示的图片:

优质内容筛选与推荐>>
1、SpringBoot 配置文件存放位置及读取顺序
2、python zbar
3、一致性哈希算法
4、selenium鼠标操作 包含右击和浮层菜单的选择
5、ubuntu16.04系统搜狗输入法的安装


长按二维码向我转账

受苹果公司新规定影响,微信 iOS 版的赞赏功能被关闭,可通过二维码转账支持公众号。

    阅读
    好看
    已推荐到看一看
    你的朋友可以在“发现”-“看一看”看到你认为好看的文章。
    已取消,“好看”想法已同步删除
    已推荐到看一看 和朋友分享想法
    最多200字,当前共 发送

    已发送

    朋友将在看一看看到

    确定
    分享你的想法...
    取消

    分享想法到看一看

    确定
    最多200字,当前共

    发送中

    网络异常,请稍后重试

    微信扫一扫
    关注该公众号





    联系我们

    欢迎来到TinyMind。

    关于TinyMind的内容或商务合作、网站建议,举报不良信息等均可联系我们。

    TinyMind客服邮箱:support@tinymind.net.cn