当前位置: 首页 > news >正文

12. Mybatis 多表查询 动态 SQL

目录

1. 数据库字段和 Java 对象不一致

2. 多表查询

3. 动态 SQL 使用

4. if 标签

5.  trim 标签

6. where 标签 

7. set 标签 

8. foreach 标签

9. 通过注解实现

9.1 查找所有数据 

9.2 通过 id 查找


1. 数据库字段和 Java 对象不一致

我们先来看一下数据库中的数据:

 接下来,我们在之前代码的基础上修改字段的名称:

/*** 数据库字段和 Java 对象不完全一致*/
@Data
public class User {private Integer id;private String name;private String pwd;private String photo;private Date createtime;private Date updatetime;
}
@Slf4j
@SpringBootTest
class UserMapperTest {@Autowiredprivate UserMapper userMapper;@Testvoid queryAll() {List<User> users = userMapper.queryAll();log.info(users.toString());}@BeforeEachvoid setUp() {log.info("before...");}@AfterEachvoid tearDown() {log.info("after...");}
}

可以看到能够获取数据,但是对应字段的值为 null 了: 

因为数据库的字段命名规则和 Java 的命名规则不一致,数据库命名:字母小写,以下划线分割;Java 属性命名:小驼峰,第一个英文单词首字母小写,其他英文单词首字母大写。

一个 xml 文件中,可以存在多个 resultMap,只需要 id 不同即可:

List<User> queryAllMap();
 <resultMap id="BaseMap" type="com.example.demo.model.User"><id property="id" column="id"></id><result property="name" column="username"></result><result property="pwd" column="password"></result></resultMap><select id="queryAllMap" resultMap="BaseMap">select * from userinfo</select>
@Testvoid queryAllMap() {List<User> users = userMapper.queryAllMap();log.info(users.toString());}

此时,我们可以看到成功查询到数据: 

 那么具体的关系如下图标注所示:

2. 多表查询

我们再新建一张表:

-- 创建⽂章表
drop table if exists articleinfo;
create table articleinfo(id int primary key auto_increment,title varchar(100) not null,content text not null,createtime datetime default now(),updatetime datetime default now(),uid int not null,rcount int not null default 1,`state` int default 1
)default charset 'utf8mb4';

如下图所示: 

添加文章的数据:

-- ⽂章添加测试数据
insert into articleinfo(title,content,uid)values('Java','Java正⽂',1);

文章添加数据后,如下图所示: 

首先是 SQL 语句的多表查询:

select * from articleinfo ta 
left join userinfo tb on ta.uid = tb.id;

接下来通过 Mybatis 实现:

首先新建 ArticleInfo 类: 

@Data
public class ArticleInfo {private Integer id;private String title;private String content;private Date createtime;private Date updatetime;private Integer rcount;private User user;
}

新建 ArticleMapper.xml 文件:

<resultMap id="BaseMap" type="com.example.demo.model.ArticleInfo"><id property="id" column="id"></id><result property="title" column="title"></result><result property="content" column="content"></result><result property="createtime" column="createtime"></result><result property="updatetime" column="updatetime"></result><association property="user" resultMap="com.example.demo.mapper.UserMapper.BaseMap"></association></resultMap><select id="queryArticle" resultMap="BaseMap">select *from articleinfo taleft join userinfo tb on ta.uid = tb.id</select>

添加测试类:

@Slf4j
@SpringBootTest
class ArticleMapperTest {@Autowiredprivate ArticleMapper articleMapper;@Testvoid queryArticle() {List<ArticleInfo> articleInfos = articleMapper.queryArticle();log.info(articleInfos.toString());}
}

运行结果如下图所示:

我们可以看到上述方式的结果显示的不够完整且需要输入的 SQL 语句过多。


接下来,我们通过另一种方式来实现:

List<ArticleInfo> queryArticle2();

在 ArticleMapper.xml 文件中添加以下配置:

<resultMap id="BaseMap2" type="com.example.demo.model.ArticleInfo"><id property="id" column="id"></id><result property="title" column="title"></result><result property="content" column="content"></result><result property="createtime" column="createtime"></result><result property="updatetime" column="updatetime"></result><result property="userId" column="userid"></result><result property="username" column="username"></result></resultMap><select id="queryArticle2" resultMap="BaseMap2">selectta.*,tb.id as userid,tb.username as usernamefrom articleinfo taleft join userinfo tb on ta.uid = tb.id</select>

添加测试类:

@Testvoid queryArticle2() {List<ArticleInfo> articleInfos = articleMapper.queryArticle2();log.info(articleInfos.toString());}

查询数据如下图所示:

需要注意,在实际的开发中,要尽量避免使用 *,无论数据库中有多少字段都需要一一罗列出来

如下所示: 

<resultMap id="BaseMap2" type="com.example.demo.model.ArticleInfo"><id property="id" column="id"></id><result property="title" column="title"></result><result property="content" column="content"></result><result property="createtime" column="createtime"></result><result property="updatetime" column="updatetime"></result><result property="userId" column="userid"></result><result property="username" column="username"></result></resultMap><select id="queryArticle2" resultMap="BaseMap2">selectta.id as id,ta.title as title,ta.content as content,ta.createtime as createtime,ta.updatetime as updatetime,tb.id as userid,tb.username as usernamefrom articleinfo taleft join userinfo tb on ta.uid = tb.id</select>

3. 动态 SQL 使用

在实际的应用中,并不是每个信息都是必填的,也就是动态 SQL根据输入参数的不同动态的拼接 SQL。

我们先来看一下表中现有的数据:

 接下来,我们插入数据:

void insert(ArticleInfo articleInfo);
<insert id="insert">insert into articleinfo(title,content,uid,state)values (#{title},#{content},#{userId},#{state})</insert>
 @Testvoid insert() {ArticleInfo articleInfo = new ArticleInfo();articleInfo.setTitle("测试文章");articleInfo.setContent("测试文章内容");articleInfo.setUserId(1);articleInfo.setState(null);articleMapper.insert(articleInfo);}

可以看到,上面我们是自行将 state 的值设置为了 null,那么如果我们没有给这个字段赋值呢?

修改 XML 文件: 

 <insert id="insert">insert into articleinfo(title,content,uid)values (#{title},#{content},#{userId})</insert>

 可以看到当我们没有对 state 赋值时,进行了自动默认赋值为1:

那么,这显然是不符合我们的预期的,我们想要实现的是当用户没有输入数据时,应该为默认值;输入数据时,显示为输入的数据。此时就需要用到标签了。

4. <if> 标签

我们的目标是根据用户输入的情况,动态拼接 SQL。

void insertByCondition(ArticleInfo articleInfo);
<insert id="insertByCondition">insert into articleinfo(title,content,uid<if test="state!=null">,state</if>)values(#{title},#{content},#{userId}<if test="state!=null">,#{state}</if>)</insert>
@Testvoid insertByCondition() {ArticleInfo articleInfo = new ArticleInfo();articleInfo.setTitle("测试文章2");articleInfo.setContent("测试文章内容2");articleInfo.setUserId(1);articleMapper.insert(articleInfo);}

 由于我们并没有设置 state 的状态,因此默认为1:

接下来我们设置 state 为0:

@Testvoid insertByCondition() {ArticleInfo articleInfo = new ArticleInfo();articleInfo.setTitle("测试文章3");articleInfo.setContent("测试文章内容3");articleInfo.setUserId(1);articleInfo.setState(0);articleMapper.insertByCondition(articleInfo);}

可以看到成功运行: 

 当我们需要对多个字段应用 if 标签时,会存在报错:

如果统一把逗号放在字段前面,当第一个字段为 null 时,整个 SQL 的最前面就会多一个逗号;如果统一把逗号放在字段后面,当最后一个字段为 null 时,整个 SQL 的最后面会多一个逗号。

5. <trim> 标签

上面的插入数据功能,如果所有字段都是非必填项,就考虑使用标签结合标签,对多个字段都采取动态生成的方式。 标签中有如下属性:

  • prefix:表示整个语句块,以prefix的值作为前缀
  • suffix:表示整个语句块,以suffix的值作为后缀
  • prefixOverrides:表示整个语句块要去除掉的前缀
  • suffixOverrides:表示整个语句块要去除掉的后缀

 使用 <trim> 标签:

<insert id="insertByCondition">insert into articleinfo<trim prefix="(" suffix=")" prefixOverrides="," suffixOverrides=","><if test="title!=null">title,</if><if test="content!=null">content,</if><if test="userId!=null">uid,</if><if test="state!=null">state</if></trim>values<trim prefix="(" suffix=")" prefixOverrides="," suffixOverrides=","><if test="title!=null">#{title},</if><if test="content!=null">#{content},</if><if test="userId!=null">#{content},</if><if test="state!=null">#{state},</if></trim></insert>

可以看到此时能够正确执行: 

6. <where> 标签 

当我们需要使用 where 语句进行条件筛选时: 

List<ArticleInfo> queryBycondition(@Param("uid") Integer uid,@Param("state")Integer state);
<select id="queryBycondition" resultType="com.example.demo.model.ArticleInfo">select * from articleinfowhere<if test="uid!=null">uid = #{uid}</if><if test="state!=null">and state=#{state}</if></select>
@Testvoid queryBycondition() {List<ArticleInfo> articleInfos = articleMapper.queryBycondition(1,1);log.info(articleInfos.toString());}

可以看到成功执行: 

此时我们修改代码如下:

 @Testvoid queryBycondition() {List<ArticleInfo> articleInfos = articleMapper.queryBycondition(1,null);log.info(articleInfos.toString());}

依然可以成功执行: 

 当我们修改代码如下时:

 @Testvoid queryBycondition() {List<ArticleInfo> articleInfos = articleMapper.queryBycondition(null,1);log.info(articleInfos.toString());}

产生报错信息: 

添加语句 1 = 1,继续修改代码如下: 

<select id="queryBycondition" resultType="com.example.demo.model.ArticleInfo">select * from articleinfowhere 1 = 1<if test="uid!=null">and uid = #{uid}</if><if test="state!=null">and state=#{state}</if></select>

此时可以看到成功执行: 


接下来,我们使用 where 标签实现以上功能。

在 XML 文件中,添加以下语句: 

<select id="queryBycondition" resultType="com.example.demo.model.ArticleInfo">select * from articleinfo<where><if test="uid!=null">and uid = #{uid}</if><if test="state!=null">and state=#{state}</if></where></select>

可以已经生成了 where 并且去掉了 and : 

当两个字段均为 null 时,可以看到直接去掉了 where:

@Testvoid queryBycondition() {List<ArticleInfo> articleInfos = articleMapper.queryBycondition(null,null);log.info(articleInfos.toString());}

综上,我们可以知道 where 标签具有以下作用:

  1. 生成 where 关键字
  2. 去除多余的 and
  3. 如果没有 where 条件,就不会生成 where 关键字

7. <set> 标签 

void updateByCondition(@Param("uid") Integer uid,@Param("state")Integer state);
<update id="updateByCondition">update articleinfoset<if test="uid!=null">uid = #{uid},</if><if test="state!=null">state = #{state},</if></update>
@Testvoid updateByCondition() {articleMapper.updateByCondition(1,null);}

运行后,产生以下报错:

接下来,我们使用 set 标签:

<update id="updateByCondition">update articleinfo<set><if test="uid!=null">uid = #{uid},</if><if test="state!=null">state = #{state},</if></set></update>

运行成功: 

综上,我们可以看到 set 标签的作用:

  1. 生成 set 关键字
  2. 去除最后一个逗号(也可以使用 trim 标签)

8. <foreach> 标签

对集合进行遍历时可以使用该标签。标签有如下属性:

  • collection:绑定方法参数中的集合,如 List,Set,Map或数组对象
  • item:遍历时的每⼀个对象
  • open:语句块开头的字符串
  • close:语句块结束的字符串
  • separator:每次遍历之间间隔的字符串

因此,我们来通过 foreach 标签实现以下目标:

 接下来我们通过代码实现:

void batchDelete(List<Integer> ids);
<delete id="batchDelete">delete from articleinfo where id in<foreach collection="list" open="(" close=")" separator="," item="id">#{id}</foreach></delete>
@Testvoid batchDelete() {List<Integer> ids = Arrays.asList(2,3,4,5,6,10,11);articleMapper.batchDelete(ids);}

可以看到成功运行: 

表中相应的数据也删除了: 

注意: 

还需要注意的是 collection 也可以是参数的名称:

9. 通过注解实现

Mybatis 的实现有两种方式:

  • xml
  • 注解

9.1 查找所有数据 

接下来,我们来看一下如何通过注解来实现:

@Mapper
public interface UserMapper2 {@Select("select * from userinfo")List<User> queryAll();
}
@Slf4j
@SpringBootTest
class UserMapper2Test {@Autowiredprivate UserMapper2 userMapper2;@Testvoid queryAll() {List<User> userList = userMapper2.queryAll();log.info(userList.toString());}
}

运行结果如下:

9.2 通过 id 查找

@Mapper
public interface UserMapper2 {@Select("select * from userinfo where id = #{uid}")User queryById(Integer aaa);
}
@Slf4j
@SpringBootTest
class UserMapper2Test {@Autowiredprivate UserMapper2 userMapper2;@Testvoid queryById() {User user = userMapper2.queryById(1);log.info(user.toString());}
}

可以看到运行结果如下: 

一个项目中,注解和 XML 的方式可以并存,对于简单的 SQL 使用注更加方便,但是对于动态 SQL 注解写起来非常麻烦。


相关文章:

12. Mybatis 多表查询 动态 SQL

目录 1. 数据库字段和 Java 对象不一致 2. 多表查询 3. 动态 SQL 使用 4. if 标签 5. trim 标签 6. where 标签 7. set 标签 8. foreach 标签 9. 通过注解实现 9.1 查找所有数据 9.2 通过 id 查找 1. 数据库字段和 Java 对象不一致 我们先来看一下数据库中的数…...

操作系统专栏1-内存管理from 小林coding

操作系统专栏1-内存管理 虚拟地址内存管理方案分段分页页表单级页表多级页表TLB 段页式内存管理Linux内存管理 malloc工作方式操作系统内存回收回收的内存种类 预读失败和缓存污染问题预读机制预读机制失效解决方案缓存污染 内核对虚拟内存的表示内核对内核空间的表示直接映射区…...

SpringCloud远程服务调用

下面介绍在SpringCloud中如何使用openfeign实现远程服务调用 1.在字典服务中有这么2个接口 Api(tags "数据字典接口") RestController RequestMapping("/admin/cmn/dict/") CrossOrigin public class DictController {Autowiredprivate DictService dic…...

Arcgis通过模型构建器计算几何坐标

模型 模型中&#xff0c;先添加字段&#xff0c;再计算字段 计算字段 模型的计算字段中&#xff0c;表达式是类似这样写的&#xff0c;其中Xmin表示X坐标&#xff0c;Ymin表示Y坐标 !Shape.extent.Xmin!...

java设计模式-工厂模式(下)

接java设计模式-工厂模式&#xff08;上&#xff09; 抽象工厂模式 针对耳机的生产需求&#xff0c;我们可以知道&#xff0c;刚才的工厂已经不满足了&#xff0c;因为只是生产一类产品-手机&#xff0c;但是现在我们需要的工厂类是要生产一个产品族&#xff08;手机和耳机&a…...

深蓝学院C++基础与深度解析笔记 第13章 模板

1. 函数模板 ● 使用 template 关键字引入模板&#xff1a; template<typename T> //声明&#xff1a;T模板形参void fun(T); // T 函数形参template<typename T> //定义void fun(T) {...}– 函数模板不是函数 –…...

装饰器模式——扩展系统功能

1、简介 1.1、概述 对新房进行装修并没有改变房屋用于居住的本质&#xff0c;但它可以让房子变得更漂亮、更温馨、更实用、更能满足居家的需求。在软件设计中&#xff0c;也有一种类似新房装修的技术可以对已有对象&#xff08;新房&#xff09;的功能进行扩展&#xff08;装…...

无涯教程-jQuery - jQuery.get( url, data, callback, type )方法函数

jQuery.get(url&#xff0c;[data]&#xff0c;[callback]&#xff0c;[type])方法使用GET HTTP请求从服务器加载数据。 该方法返回XMLHttpRequest对象。 jQuery.get( url, [data], [callback], [type] ) - 语法 $.get( url, [data], [callback], [type] ) 这是此方法使用的…...

【Vue3】递归组件

1. 递归组件mock数据 App.vue <template><div><Tree :data"data"></Tree></div> </template><script setup lang"ts"> import { reactive } from vue; import Tree from ./components/Tree.vue; interface Tr…...

【Python】数据分析+数据挖掘——探索Pandas中的索引与数据组织

前言 在数据科学和数据分析领域&#xff0c;Pandas是一个备受喜爱的Python库。它提供了丰富的数据结构和灵活的工具&#xff0c;帮助我们高效地处理和分析数据。其中&#xff0c;索引在Pandas中扮演着关键角色&#xff0c;它是一种强大的数据组织和访问机制&#xff0c;使我们…...

matlab进阶:求解在约束条件下的多元目标函数最值(fmincon函数详解)

&#x1f305;*&#x1f539;** φ(゜▽゜*)♪ **&#x1f539;*&#x1f305; 欢迎来到馒头侠的博客&#xff0c;该类目主要讲数学建模的知识&#xff0c;大家一起学习&#xff0c;联系最后的横幅&#xff01; 喜欢的朋友可以关注下&#xff0c;私信下次更新不迷路&#xff0…...

Kotlin知识点

Kotlin 是 Google 推荐的用于创建新 Android 应用的语言。使用 Kotlin&#xff0c;可以花更短的时间编写出更好的 Android 应用。 基础 Kotlin 程序必须具有主函数&#xff0c;这是 Kotlin 编译器在代码中开始编译的特定位置。主函数是程序的入口点&#xff0c;或者说是起点。…...

亚马逊云科技联合霞光社发布《2013~2023中国企业全球化发展报告》

中国企业正处于全球聚光灯下。当企业全球化成为时代发展下的必然趋势&#xff0c;出海也从“可选项”变为“必选项”。中国急速扩大的经济规模&#xff0c;不断升级的研发和制造能力&#xff0c;都在推动中国企业不断拓宽在全球各行业的疆域。 过去十年&#xff0c;是中国企业…...

【解析excel】利用easyexcel解析excel

【解析excel】利用easyexcel解析excel POM监听类工具类测试类部分测试结果备注其他 EasyExcel Java解析、生成Excel比较有名的框架有Apache poi、jxl。但他们都存在一个严重的问题就是非常的耗内存&#xff0c;poi有一套SAX模式的API可以一定程度的解决一些内存溢出的问题&…...

JQuery操作单选按钮Radio和复选框checkbox

获取选中值&#xff1a; $(input:radio:checked).val()&#xff1b;$("input[typeradio]:checked").val();$("input[namerd]:checked").val();$("input[idrand_question]:checked").val();设置第一个Radio为选中值&#xff1a; $(input:radio:…...

7.28 作业 QT

手动完成服务器的实现&#xff0c;并具体程序要注释清楚: widget.h: #ifndef WIDGET_H #define WIDGET_H#include <QWidget> #include <QTcpServer> //服务器类 #include <QTcpSocket> //客户端类 #include <QMessageBox> //对话框类 #include …...

HTML <pre> 标签

定义和用法 pre 元素可定义预格式化的文本。被包围在 pre 元素中的文本通常会保留空格和换行符。而文本也会呈现为等宽字体。 <pre> 标签的一个常见应用就是用来表示计算机的源代码。 可以导致段落断开的标签(例如标题、"><p> 和 标签"><a…...

查询结果元数据-MetaData对象、数据库工具类的封装、通过反射实现数据查询的封装

六、查询结果元数据-MetaData对象 七、数据库工具类的封装 1、PropertieUtil类 2、DbUtil类 3、DBHepler类 查询&#xff1a; 4、TestDb测试类&#xff1a; 更新&#xff1a; 1&#xff09;插入&#xff1a; 2&#xff09;修改&#xff1a; 3&#xff09;删除&#xff1a; 查…...

【Minio中间件】上传图片并Vue回显

流程&#xff1a; 目录 1.文件服务器Minio的安装 1.1 下载Minio安装后&#xff0c;新建1个data文件夹。并在该安装目录cmd 敲命令。注意不要进错目录。依次输入 1.2 登录Minio网页端 1.3 先建1个桶&#xff08;buckets&#xff09;&#xff0c;点击create a bucket 2. Spr…...

Jmeter配置不同业务请求比例,应对综合场景压测

需求&#xff1a; 每次向服务器发出请求时&#xff0c;先生成一个随机数&#xff0c;我们对随机数的取值划分若干个范围&#xff08;对应若干个业务请求&#xff09;&#xff0c;然后对随机数进行判断&#xff0c;当随机数落在某个范围内&#xff0c;就可以执行对应的请求。比…...

KubeSphere 容器平台高可用:环境搭建与可视化操作指南

Linux_k8s篇 欢迎来到Linux的世界&#xff0c;看笔记好好学多敲多打&#xff0c;每个人都是大神&#xff01; 题目&#xff1a;KubeSphere 容器平台高可用&#xff1a;环境搭建与可视化操作指南 版本号: 1.0,0 作者: 老王要学习 日期: 2025.06.05 适用环境: Ubuntu22 文档说…...

LBE-LEX系列工业语音播放器|预警播报器|喇叭蜂鸣器的上位机配置操作说明

LBE-LEX系列工业语音播放器|预警播报器|喇叭蜂鸣器专为工业环境精心打造&#xff0c;完美适配AGV和无人叉车。同时&#xff0c;集成以太网与语音合成技术&#xff0c;为各类高级系统&#xff08;如MES、调度系统、库位管理、立库等&#xff09;提供高效便捷的语音交互体验。 L…...

国防科技大学计算机基础课程笔记02信息编码

1.机内码和国标码 国标码就是我们非常熟悉的这个GB2312,但是因为都是16进制&#xff0c;因此这个了16进制的数据既可以翻译成为这个机器码&#xff0c;也可以翻译成为这个国标码&#xff0c;所以这个时候很容易会出现这个歧义的情况&#xff1b; 因此&#xff0c;我们的这个国…...

业务系统对接大模型的基础方案:架构设计与关键步骤

业务系统对接大模型&#xff1a;架构设计与关键步骤 在当今数字化转型的浪潮中&#xff0c;大语言模型&#xff08;LLM&#xff09;已成为企业提升业务效率和创新能力的关键技术之一。将大模型集成到业务系统中&#xff0c;不仅可以优化用户体验&#xff0c;还能为业务决策提供…...

python打卡day49

知识点回顾&#xff1a; 通道注意力模块复习空间注意力模块CBAM的定义 作业&#xff1a;尝试对今天的模型检查参数数目&#xff0c;并用tensorboard查看训练过程 import torch import torch.nn as nn# 定义通道注意力 class ChannelAttention(nn.Module):def __init__(self,…...

Prompt Tuning、P-Tuning、Prefix Tuning的区别

一、Prompt Tuning、P-Tuning、Prefix Tuning的区别 1. Prompt Tuning(提示调优) 核心思想:固定预训练模型参数,仅学习额外的连续提示向量(通常是嵌入层的一部分)。实现方式:在输入文本前添加可训练的连续向量(软提示),模型只更新这些提示参数。优势:参数量少(仅提…...

SciencePlots——绘制论文中的图片

文章目录 安装一、风格二、1 资源 安装 # 安装最新版 pip install githttps://github.com/garrettj403/SciencePlots.git# 安装稳定版 pip install SciencePlots一、风格 简单好用的深度学习论文绘图专用工具包–Science Plot 二、 1 资源 论文绘图神器来了&#xff1a;一行…...

从零实现富文本编辑器#5-编辑器选区模型的状态结构表达

先前我们总结了浏览器选区模型的交互策略&#xff0c;并且实现了基本的选区操作&#xff0c;还调研了自绘选区的实现。那么相对的&#xff0c;我们还需要设计编辑器的选区表达&#xff0c;也可以称为模型选区。编辑器中应用变更时的操作范围&#xff0c;就是以模型选区为基准来…...

STM32F4基本定时器使用和原理详解

STM32F4基本定时器使用和原理详解 前言如何确定定时器挂载在哪条时钟线上配置及使用方法参数配置PrescalerCounter ModeCounter Periodauto-reload preloadTrigger Event Selection 中断配置生成的代码及使用方法初始化代码基本定时器触发DCA或者ADC的代码讲解中断代码定时启动…...

Java - Mysql数据类型对应

Mysql数据类型java数据类型备注整型INT/INTEGERint / java.lang.Integer–BIGINTlong/java.lang.Long–––浮点型FLOATfloat/java.lang.FloatDOUBLEdouble/java.lang.Double–DECIMAL/NUMERICjava.math.BigDecimal字符串型CHARjava.lang.String固定长度字符串VARCHARjava.lang…...