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.
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语句。
接下来,我将商品类型的查询注释掉
可以从控制台的日志信息里看出,我只进行了一次查询。但是却传了两个参数。是因为我这里只需要商品信息的内容,而不需要显示商品信息类型,懒加载就不会去加载我不需要的数据。也就不会去查询商品类型表。
所以说呢,懒加载就是当你在进行联表查询的时候,需要哪张表的数据它才会去对哪张表的数据进行查询,不需要的则不会去查询。
同样,不管是一对多或者是多对一的查询(一对一或多对多可以理解为特殊的一对多),都是可以使用懒加载的。
下面再来两张演示的图片:
优质内容筛选与推荐>>