MyBatis—多表查询

3 篇文章 0 订阅
3 篇文章 0 订阅

多表查询

我们以一个例子来展开对于多表查询的使用。

一对一

查看订单以及相关联用户:
select bo .id , order_no, total,
bu .id user_id, bu .name , bu .age
from
b_order bo left join b_user bu on bo .user_id = bu .id

DTO 

package cn.ry.pojo.dto;
import cn.ry.pojo.BOrder;
import cn.ry.pojo.BUser;
//相当于当前类是BOrder的扩展类;
public class BOrderDto extends BOrder{
//一个订单去找用户:一个订单只能找到一个用户;
private BUser buser;
// // 一个订单去找订单详情: 一个订单可以有多个订单详情:
// private List<订单详情> 变量名;
}

mapper 

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"https://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="cn.ry.mapper.BOrderMapper">
<!-- 一对一 -->
<select id="selectOrderAndUser" resultMap="map0">
select bo.id, order_no, total,
bu.id user_id, bu.name, bu.age
from
b_order bo left join b_user bu on bo.user_id = bu.id
</select>
<resultMap type="BOrderDto" id="map0">
<id column="id" property="id"></id>
<result column="order_no" property="orderNo"/>
<result column="total" property="total"/>
<!-- 一对一的标签association
javaType:Dto类中属性类型——》自定义类型——》实体类
property:Dto中该自定义类型的属性名;
-->
<association property="buser" javaType="BUser" >
<id column="user_id" property="id" />
<result column="name" property="name"/>
<result column="age" property="age"/>
</association>
</resultMap>
</mapper>

 

一对多 

sql

查询订单以及订单详情:
select
bo .id , order_no, user_id, total,
bod .id detail_id, goods_id, main_id, price, num
from b_order bo left join b_order_detail bod on bo .id =bod .main_id

 mapper

<!-- 一对多 -->
<select id="selectOrderAndDetails" resultMap="map1" >
select
bo.id, order_no, user_id, total,
bod.id detail_id, goods_id, main_id, price, num
from b_order bo left join b_order_detail bod on bo.id=bod.main_id
</select>
<resultMap type="BOrderDto" id="map1" extends="BaseMap">
<collection property="details" ofType="BOrderDetail">
<id column="detail_id" property="id"></id>
<result column="goods_id" property="goodsId"/>
<result column="main_id" property="mainId"/>
<result column="price" property="price"/>
<result column="num" property="num"/>
</collection>
</resultMap>

 

多对多

查看用户购买了哪些商品

select
bu .id ,bu .name ,
bo .id order_id,
bod .id detail_id,
bg .id goods_id,
bg .goods_name
from b_user bu
left join b_order bo on bu .id = bo .user_id
left join b_order_detail bod on bod .main_id = bo .id
left join b_goods bg on bod .goods_id = bg .id

mapper

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"https://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="cn.ry.mapper.BUserMapper">
<resultMap type="BUser" id="BaseMap">
<id column="id" property="id"></id>
<result column="name" property="name"/>
<result column="age" property="age"/>
</resultMap>
<!-- 多对多 -->
<select id="selectUserAndGoods" resultMap="map0">
select
bu.id,bu.name,
bo.id order_id,
bod.id detail_id,
bg.id goods_id,
bg.goods_name
from b_user bu
left join b_order bo on bu.id = bo.user_id
left join b_order_detail bod on bod.main_id = bo.id
left join b_goods bg on bod.goods_id = bg.id
</select>
<resultMap type="BUserDto" id="map0" extends="BaseMap">
<collection property="orders" ofType="BOrderDto">
<id column="order_id" property="id"></id>
<collection property="details" ofType="BOrderDetailDto">
<id column="detail_id" property="id"/>
<association property="bgoods" javaType="BGoods">
<id column="goods_id" property="id"></id>
<result column="goods_name" property="goodsName"/>
</association>
</collection>
</collection>
延迟加载
延迟加载的本身是依赖于多表查询的;
延迟加载中返回值要选择resultMap;
返回的结果一定是dto;
延迟加载也可以成为按需加载;默认是没有开启的
在使用的时候需要将其设置为true;需要对 aggressiveLazyLoading 属性设置为false;
mapper.xml
</resultMap>
</mapper>

延迟加载

延迟加载的本身是依赖于多表查询的

  • 延迟加载中返回值要选择resultMap;
  • 返回的结果一定是dto;

延迟加载也可以成为按需加载;默认是没有开启的

lazyLoadingEnabled 默认值是false;
<!-- lazyLoadingEnabled:延迟加载全局开关,开启后所有关联对象
都会延迟加载;
aggressiveLazyLoading:按需加载;
开启时,任一方法的调用都会加载该对象的所有延迟加载属性,因此设置为false;
设置为false表示的意思就是按需加载;
-->
<setting name="lazyLoadingEnabled" value="true"/>
<setting name="aggressiveLazyLoading" value="false"/>

 在使用的时候需要将其设置为true;需要对aggressiveLazyLoading属性设置为false;

mapper.xml

<!-- 一对多 -->
<select id="selectOrderAndDetails" resultMap="map1" >
select * from b_order
</select>
<resultMap type="BOrderDto" id="map1" extends="BaseMap">
<!-- 延迟加载和多表查询(高级映射)的区别:
在标签(collection或者association)中,添加column属性和select属性;
select属性中:里面的内容写的是:namespace.sqlID;
表示的是:用来封装当前collection或者association的返回结果
也就是select属性值中的sqlid查询出来的应该是和ofType同等类
型;
column属性指的是:第一步查询结果中的列名——》用作参数传入到select调用的
sqlId中;
-->
<collection property="details" ofType="BOrderDetailDto" column="id"
select="selectDetails">
</collection>
</resultMap>
<!-- 按需加载,如果还需要查看订单详情信息,则调用该方法: -->
<select id="selectDetails" resultMap="map2">
select id detail_id, goods_id, main_id, price, num
from b_order_detail where main_id = #{id}
</select>
<resultMap type="BOrderDetailDto" id="map2">
<id column="detail_id" property="id"></id>
<result column="goods_id" property="goodsId"/>
<result column="main_id" property="mainId"/>
动态sql
以后主要用于多表查询的时候赋予条件。
where
where标签主要用来代替之前的where关键字,并且去掉里面的第一个and或者or;
if
和之前c:if相似,用来判断当前值是否为空;
choose
和之前c:choose一样;
foreach
<result column="price" property="price"/>
<result column="num" property="num"/>
</resultMap>

动态sql

主要用于多表查询的赋予条件

举个栗子:

String sql="select * from b_order";
if(name!=null||"".equals(name)){
sql+="where name like '%"+name+"%'";
}
if(age!=null){
sql+="where age ="+age;
}

常用标签举例:

where

主要用来替代之前的where关键字,去掉里面第一个and/or;

if

和c:if 相似,判断当前值是否为空

<if test = " 属性 != null and 属性 != '' " >
</if>
<!-- 如果不是字符串类型直接判断不等于 null 即可 -->
choose

和c:choose 一样

<choose>
<when test = "title != null" >
AND title like #{title}
</when>
<when test = "author != null and author.name != null" >
AND author_name like #{author.name}
</when>
<otherwise>
AND featured = 1
</otherwise>
</choose>
forEach
<where>
<!--
foreach和之前的c:foreach不太一样:
item:表示的是变量名,等同于以前的var;
collection:如果传入进来的是数组——》collection="array";
set
代替修改语句中的set关键字,并且去掉最后一个条件的","。
trim
sql
作业
用户表: id name age dept_id role_id;
部门表: id dept_name;
角色表: id role_id;
资源表: id resource_name url;
权限表: id role_id resource_id
查询用户并且查看关联的部门信息以及角色;(一对一)
查询部门信息并查看该部门下的用户信息;(一对多)
查看用户信息,并且显示用户所拥有的的资源信息;
延迟加载 一对一
缓存
如果传入进来的是集合——》collection="list"
如果传入的是map:java代码中需要将list放入到map中,再传值;
collection="map中的键"
-->
<foreach item="item" index="index" collection="list"
open="ID in (" separator="," close=")" nullable="true">
#{item}
</foreach>
</where>
 set

代替修改语句中的set关键字,并且去掉最后一个条件的“ , ”;

trim
<!--
trim可以替代 where 和 set:
-->
<!-- 替代where的时候: -->
<trim prefix ="where" prefixOverrides="AND|OR">
</trim>
<!-- 替代set -->
<trim prefix="set" suffixOverrides=",">
</trim>
sql
<sql id = "xx" >
列名 , 列名
</sql>
<!-- sql 标签使用:定义固定的 sql 模板,解耦合的作用。定义好以后,配合 include 标签一块使用。 -->

缓存

 mybatis框架中包含了一级缓存和二级缓存。

一级缓存

框架中默认开启了一级缓存,一级缓存是sqlsession级别的缓存。

同一个sqlsession多次调用同一个sqlid会触发一级缓存。

只要确保是同一个sqlsession,无论mapper获取的是否相同。,直接执行同一个sqlid,都会触发一级缓存。

二级缓存

mybatis默认不开启二级缓存,所以需要手动开启

<setting name="cacheEnabled" value="true"/>

mapper级别的缓存——>不同的sqlsession调用同一个mapper文件中的同一个sqlid,会触发二级缓存。

注意事项
  • 在全局配置设置完以后需要在mapper文件中添加一个标签<cache>;
  • 需要对返回的记过对应的实体类进行序列化:implements Serializable;
  • 执行需要对SqlSession进行关闭;

分页

pageHelper

使用

<dependency>
<groupId> com.github.pagehelper </groupId>
<artifactId> pagehelper </artifactId>
<version> 最新版本 </version>
</dependency>

条件

导入 pageHelper-xxx.jar;
jsql-parser.jar;

配置拦截器插件

<plugins>
<!-- com.github.pagehelper PageHelper 类所在包名 -->
<plugin interceptor = "com.github.pagehelper.PageInterceptor" >
<!-- 使用下面的方式配置参数,后面会有所有的参数介绍 -->
<property name = "helperDialect" value = "mysql" />
</plugin>
</plugins>

 逆向工程

操作流程

正向工程操作:项目——>需求分析——>创建UML类图——>创建实体类——>表;

逆向工程操作:表——>创建实体类;

搭建

逆向工程通常创建java项目,导入逆向工程所需要的jar包和驱动包;通过xml和java代码一起实现。

xml文件配置:

<!DOCTYPE generatorConfiguration PUBLIC
"-//mybatis.org//DTD MyBatis Generator Configuration 1.0//EN"
"http://mybatis.org/dtd/mybatis-generator-config_1_0.dtd">
java
使用
<generatorConfiguration>
<!--
context:一个配置文件中可以有多个context标签;
id:表示唯一标识;
defaultModelType:
conditional:正常生成一个实体类,如果实体类中只有一个主键字段,不会生成实体
类;
flat:会为每张表生成一个实体类,实体类中包含表中所有字段;
hierarchical:
如果表中存在主键则生成主键类;
表中非主键列并且非Blob类型的列,会生成一个类,该类继承主键类
如果存在Blob类型的列,则为该类型的列生成专门的类,该类继承非主键类;
targetRuntime:目标运行环境:
-->
<context id="simple" targetRuntime="MyBatis3">
<jdbcConnection driverClass="com.mysql.cj.jdbc.Driver"
connectionURL="jdbc:mysql://localhost:3306/2303?
nullCatalogMeansCurrent=true"
userId="root"
password="root"
/>
<!--
javaModelGenerator:生成的实体类——pojo;
targetPackage:生成的目标包:
-->
<javaModelGenerator targetPackage="cn.ry.pojo" targetProject="src/"/>
<!--
sqlMapGenerator:映射文件:目录设置:
-->
<sqlMapGenerator targetPackage="cn.ry.mapper" targetProject="src/"/>
<!--
javaClientGenerator:mapper接口;
-->
<javaClientGenerator type="XMLMAPPER" targetPackage="cn.ry.mapper"
targetProject="src/"/>
<table tableName="b_order" />
</context>
</generatorConfiguration>

java代码实现:

public static void main(String[] args) throws Exception {
List<String> warnings = new ArrayList<String>();
boolean overwrite = true;
File configFile = new
File("G:\\workspace\\2403NXGC\\src\\Generator.xml");
ConfigurationParser cp = new ConfigurationParser(warnings);
Configuration config = cp.parseConfiguration(configFile);
DefaultShellCallback callback = new DefaultShellCallback(overwrite);
MyBatisGenerator myBatisGenerator = new MyBatisGenerator(config,
callback, warnings);
myBatisGenerator.generate(null);
}

 使用

区别是如果表某列设置了默认值,新增语句中,刚好没有给该列复制,此时前者赋值为null,后者赋值为默认值。

SqlSession s = SqlSessionUtil.getSqlSession();
BOrderMapper mapper = s.getMapper(BOrderMapper.class);
BOrderExample example =new BOrderExample();
//创建条件对象;
Criteria c = example.createCriteria();
//使用条件对象中的方法:
c.andOrderNoLike("%02%");
c.andTotalGreaterThan(1);
创建条件对象2;
Criteria c1 = example.createCriteria();
c1.andIdIsNotNull();
example.or(c1);
List<BOrder> list = mapper.selectByExample(example);
System.out.println(list.size());

 今天的分享到此结束了,博主创作不易,大家点个关注不迷路,我们下期再见。

  • 32
    点赞
  • 30
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值