12. Mybatis 多表查询 动态 SQL

news2024/9/27 9:29:11

目录

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

2. 多表查询

3. 动态 SQL 使用

4. 标签

5. 标签

6. 标签 

7. 标签 

8. 标签

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 {
    @Autowired
    private UserMapper userMapper;
    @Test
    void queryAll() {
        List<User> users = userMapper.queryAll();
        log.info(users.toString());
    }

    @BeforeEach
    void setUp() {
        log.info("before...");
    }

    @AfterEach
    void 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>
@Test
    void 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 ta
        left join userinfo tb on ta.uid = tb.id
    </select>

添加测试类:

@Slf4j
@SpringBootTest
class ArticleMapperTest {
    @Autowired
    private ArticleMapper articleMapper;
    @Test
    void 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">
        select
        ta.*,
        tb.id as userid,
        tb.username as username
        from articleinfo ta
        left join userinfo tb on ta.uid = tb.id
    </select>

添加测试类:

@Test
    void 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">
        select
        ta.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 username
        from articleinfo ta
        left 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>
 @Test
    void 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>
@Test
    void insertByCondition() {
        ArticleInfo articleInfo = new ArticleInfo();
        articleInfo.setTitle("测试文章2");
        articleInfo.setContent("测试文章内容2");
        articleInfo.setUserId(1);
        articleMapper.insert(articleInfo);
    }

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

接下来我们设置 state 为0:

@Test
    void insertByCondition() {
        ArticleInfo articleInfo = new ArticleInfo();
        articleInfo.setTitle("测试文章3");
        articleInfo.setContent("测试文章内容3");
        articleInfo.setUserId(1);
        articleInfo.setState(0);
        articleMapper.insert(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 articleinfo
        where
        <if test="uid!=null">
            uid = #{uid}
        </if>
        <if test="state!=null">
            and state=#{state}
        </if>
    </select>
@Test
    void queryBycondition() {
        List<ArticleInfo> articleInfos = articleMapper.queryBycondition(1,1);
        log.info(articleInfos.toString());
    }

可以看到成功执行: 

此时我们修改代码如下:

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

依然可以成功执行: 

 当我们修改代码如下时:

 @Test
    void 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 articleinfo
        where 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:

@Test
    void 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 articleinfo
        set
        <if test="uid!=null">
            uid = #{uid},
        </if>
        <if test="state!=null">
            state = #{state},
        </if>
    </update>
@Test
    void 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>
@Test
    void 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 {
    @Autowired
    private UserMapper2 userMapper2;
    @Test
    void 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 {
    @Autowired
    private UserMapper2 userMapper2;

    @Test
    void queryById() {
        User user = userMapper2.queryById(1);
        log.info(user.toString());
    }
}

可以看到运行结果如下: 

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


 

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/809318.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

冠达管理:股指预计维持震荡格局 关注汽车、酿酒等板块

冠达管理指出&#xff0c;周四A股商场冲高遇阻、小幅震动整理&#xff0c;早盘股指高开后震动上行&#xff0c;沪指盘中在3245点邻近遭遇阻力&#xff0c;午后股指逐级回落&#xff0c;轿车、金融、酿酒以及军工等职业轮番领涨&#xff0c;互联网、软件、半导体以及证券等职业震…

Git克隆文件不显示绿色勾、红色感叹号等图标

1、问题 Git和TorToiseGit安装后&#xff0c;Git克隆的文件不会显示绿色勾、红色感叹号等图标。 2、检查注册表 2.1、打开注册表 (1)WinR打开运行窗口&#xff0c;输入regedit&#xff0c;点击确定&#xff0c;打开注册表编辑器。 2.2、找如下路径 (1)找到路径 计算机\HKEY_…

Unity 性能优化四:UI耗时函数、资源加载、卸载API

UI耗时函数 1.1 Canvas.SendWillRenderCanvases 这个函数是由于自身UI的更新&#xff0c;产生的耗时 1. 这里更新的是vertex 属性&#xff0c;比如 color、tangent、position、uv&#xff0c;修改recttransform的position、scale&#xff0c;rotation并不会导致顶点属性改变…

想测试入门就必须要懂的软件开发流程

从事软件测试行业&#xff0c;每天面对的被测对象都是软件。如果想要更好的去完成测试工作&#xff0c;首先需要对被测对象&#xff0c;也就是对软件要有基本的了解。 软件 与计算机系统操作有关的计算机程序、可能有的文件、文档及数据。 程序好理解&#xff0c;就是可以操…

JS正则表达式:常用正则手册/RegExp/正则积累

一、正则基础语法 JavaScript 正则表达式 | 菜鸟教程 JS正则表达式语法大全&#xff08;非常详细&#xff09; 二、使用场景 2.1、校验中国大陆手机号的正则表达式 正则 /^1[3456789]\d{9}$/解释 序号正则解释1^1以数字 1 开头2[3456789]第二位可以是 3、4、5、6、7、8、…

MybatisPlus拓展篇

文章目录 逻辑删除通用枚举字段类型处理器自动填充功能防全表更新与删除插件MybatisX快速开发插件插件安装逆向工程常见需求代码生成 乐观锁问题引入乐观锁的使用效果测试 代码生成器执行SQL分析打印多数据源 逻辑删除 逻辑删除的操作就是增加一个字段表示这个数据的状态&…

本地仓库推送至远程仓库

1. 本地生成ssh密钥对 ssh-keygen -t rsa -C 邮箱2. 添加公钥到gitlab/github/gitee上 打开C:\Users\用户名\.ssh目录下生成的密钥文件id_rsa.pub&#xff0c;把内容复制到如下文本框中 删除Expiration date显示的日期&#xff0c;公钥有效期变成永久&#xff0c;之后点Add K…

LeetCode 刷题 数据结构 数组 485 最大连续1的个数

给定一个二进制数组 nums &#xff0c; 计算其中最大连续 1 的个数。 示例 1&#xff1a; 输入&#xff1a;nums [1,1,0,1,1,1] 输出&#xff1a;3 解释&#xff1a;开头的两位和最后的三位都是连续 1 &#xff0c;所以最大连续 1 的个数是 3.示例 2: 输入&#xff1a;nums […

ROS中使用RealSense-D435

文章目录 D435简介RealSense的SDK2.0安装方法1&#xff1a;直接利用安装源安装注册服务器公匙将服务器添加到存储库列表安装库 方法2&#xff1a;利用源码安装GitHub下载librealsense安装编译依赖运行脚本cmake编译 软件显示 ROS接口安装启动节点查看话题rviz显示点云 Python接…

MySQL中IN的取值范围较大时会导致索引失效

一&#xff1a;分析MySQL In查询为什么所有不生效 结论&#xff1a;IN肯定会走索引&#xff0c;但是当IN的取值范围较大时会导致索引失效&#xff0c;走全表扫描 navicat可视化工具使用explain函数查看sql执行信息 1.1 场景1&#xff1a;当IN中的取值只有一个主键时 我们只需要…

怎么在线制作证件?教你一键生成证件照

无论是申请身份证、护照、驾照还是学生证&#xff0c;都需要一张清晰、规范的证件照。但是&#xff0c;为了拍摄一张完美的证件照&#xff0c;需要付出不少时间和精力。而现在&#xff0c;我们可以使用压缩图网站提供的证件照制作工具&#xff0c;轻松制作出一张清晰、规范的证…

力扣刷题记录---利用python实现链表的基本操作

文章目录 前言一、利用python实现链表的基本操作1.节点的定义使用类实现&#xff1a;1.链表的定义使用类实现&#xff1a;3.判断是否为空函数实现&#xff1a;4.链表长度函数实现&#xff1a;5.遍历链表函数实现&#xff1a;6.头插法函数实现&#xff1a;7.尾插法函数实现&…

手把手一起上传本地项目至Gitee仓库

1、Gitee新建仓库 创建自己的Gitee账号&#xff0c;新建仓库&#xff0c;如图所示&#xff1a; 根据自己的项目情况&#xff0c;填写仓库信息&#xff0c;如图所示&#xff1a; 仓库创建完成&#xff0c;如图所示&#xff1a; 2、下载Git 下载地址可用链接: https://registry…

xxl-Job分布式任务调度

1.概述 1.1 什么是任务调度 我们可以先思考一下业务场景的解决方案&#xff1a; 某电商系统需要在每天上午10点&#xff0c;下午3点&#xff0c;晚上8点发放一批优惠券。某银行系统需要在信用卡到期还款日的前三天进行短信提醒。某财务系统需要在每天凌晨0:10结算前一天的财…

流数据湖平台Apache Paimon(一)概述

文章目录 第1章 概述1.1 简介1.2 核心特性1.3 基本概念1.3.1 Snapshot1.3.2 Partition1.3.3 Bucket1.3.4 Consistency Guarantees一致性保证 1.4 文件布局1.4.1 Snapshot Files1.4.2 Manifest Files1.4.3 Data Files1.4.4 LSM Trees 第1章 概述 1.1 简介 Flink 社区希望能够将…

新材料技术的优势

目录 1.什么是新材料技术 2.新材料技术给人类带来了哪些便利 3.新材料技术未来的发展趋势 1.什么是新材料技术 新材料技术指的是通过科学和工程技术的手段开发和应用全新的材料&#xff0c;以满足特定的需求和应用。新材料技术是材料科学和工程领域的重要研究方向&#xff0…

【Java】使用JDBC操作MySQL 8

文章目录 1. JDBC概述2. JDBC快速入门2.1 下载驱动jar包2.2 数据准备2.3 创建工程2.4 编写代码 3. JDBC API详解3.1 DriverManager3.2 Connection3.2.1 获取执行SQL对象3.2.1 管理事务 3.3 Statement3.3.1 执行DML语句3.3.2 执行DDL语句 3.4 ResultSet3.4.1 ResultSet对象方法3…

解读 Zebec Protocol 发布的最新路线图,向 Web2 世界跨越的野望

近期&#xff0c;流支付协议 Zebec Protocol 发布了最新的路线图&#xff0c;揭示了生态在未来一年的全新发展规划。目前&#xff0c; Zebec Protocol 生态打造了一套全新的产品矩阵&#xff0c;包括模块化 Layer3 链 Nautilus Chain 、流支付应用 Zebec APP 以及薪酬管理协议 …

小红书怎么推广 方法经验总结

大家好&#xff0c;我是网媒智星&#xff0c;今天跟大家分享一下小红书怎么推广&#xff0c;总结一些方法经验。 小红书上的引流变现逻辑包括以下步骤&#xff1a; 选题—封面标题—内容评论—钩子—私域—成交—裂变 如果你希望在小红书上进行正确、安全的引流&#xff0c;…

Virtualbox虚拟机中Ubuntu忘记密码

1、首先重新启动Ubuntu系统&#xff0c;鼠标快速点一下Virtualbox虚拟机窗口获取焦点&#xff0c;然后按住shift键&#xff0c;以调出grub启动菜单。 2、根据提示按下键盘E键进入编辑模式&#xff0c;向下移动光标&#xff0c;将如下"ro quiet splash $vt_handoff"部…