表关联查询,说道表关联查询就要说道数据库。
数据库大致分两种,关系型数据库和非关系型数据库。
像我们一般用到的数据库Sql Server,MySQL,Oracle等等,这些都是关系型数据库。
这里有一个博客,就详细的写出来关系型数据库和非关系型数据库。
关与数据库就不多说了。来说说我们的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语句。
接下来,我将商品类型的查询注释掉
可以从控制台的日志信息里看出,我只进行了一次查询。但是却传了两个参数。是因为我这里只需要商品信息的内容,而不需要显示商品信息类型,懒加载就不会去加载我不需要的数据。也就不会去查询商品类型表。
所以说呢,懒加载就是当你在进行联表查询的时候,需要哪张表的数据它才会去对哪张表的数据进行查询,不需要的则不会去查询。
同样,不管是一对多或者是多对一的查询(一对一或多对多可以理解为特殊的一对多),都是可以使用懒加载的。
下面再来两张演示的图片: