多表查询
我们以一个例子来展开对于多表查询的使用。
一对一
查看订单以及相关联用户:select bo .id , order_no, total,bu .id user_id, bu .name , bu .agefromb_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
查询订单以及订单详情:selectbo .id , order_no, user_id, total,bod .id detail_id, goods_id, main_id, price, numfrom 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>
多对多
查看用户购买了哪些商品
selectbu .id ,bu .name ,bo .id order_id,bod .id detail_id,bg .id goods_id,bg .goods_namefrom b_user buleft join b_order bo on bu .id = bo .user_idleft join b_order_detail bod on bod .main_id = bo .idleft 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>
条件
配置拦截器插件
<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());
今天的分享到此结束了,博主创作不易,大家点个关注不迷路,我们下期再见。