MyBatis 实现动态 SQL

 MyBatis 中的动态 SQL 就是SQL语句可以根据不同的情况情况来拼接不同的sql。

本文会介绍 xml注解 两种方式的动态SQL实现方式。

XML的实现方式

先创建一个数据表,SQL代码如下:

DROP TABLE IF EXISTS `userinfo`;
CREATE TABLE `userinfo`  (
  `id` int(11) NULL DEFAULT NULL,
  `username` varchar(127) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL,
  `gender` tinyint(4) NULL DEFAULT NULL COMMENT '1-男 2-⼥ ',
  `delete_flag` tinyint(4) NULL DEFAULT 0 COMMENT '0-正常, 1-删除',
  `create_time` datetime NULL DEFAULT CURRENT_TIMESTAMP,
  `update_time` datetime NULL DEFAULT CURRENT_TIMESTAMP
) ENGINE = InnoDB CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci ROW_FORMAT = Dynamic;

SET FOREIGN_KEY_CHECKS = 1;

数据库表和JAVA对象的对应如下:

 

平时在注册账号时会有一些非必填项,而我们就可以使用 <if> 标签来跟据条件进行动态的SQL语句的添加。

接口定义:

@Mapper
public interface Userinfo {
    Integer addUserinfo(User user);
}

<if>标签

语法:

<if test = "条件"> 语句块 </if>

如果 test 后面的条件判断结果为 true,那么就将后面的语句块拼接到最终的 SQL 语句中。

XML的实现代码如下:

<insert id="addUserinfo">
    insert into userinfo(id, username,
                <if test="gender != null">
                    gender,
                </if>
                <if test="deleteFlag != null">
                    delete_flag
                </if>
    ) values (
                #{id},#{username},
                <if test="gender != null">
                  #{gender},
                </if>
                <if test="deleteFlag != null">
                    #{deleteFlag}
                </if>
    );
</insert>

注意:test中的gender和deleteFlag,是传入对象中的属性,不是数据库字段。

执行以下测试代码:

@Test
void addUserinfo() {
    User user = new User();
    user.setId(2);
    user.setUsername("zhangsan");
    user.setDeleteFlag(0);
    //此时gender为空
    userinfo.addUserinfo(user);
}

运行之后我们从日志中可以看出最终执行的SQL语句中并没有 gender

而当我们令gender不为空:

user.setGender(1);

但是此时我们的代码还有一个隐藏BUG,比如当deleteFlag为空时:

@Test
void addUserinfo() {
    User user = new User();
    user.setId(2);
    user.setUsername("zhangsan");
    //user.setDeleteFlag(0);
    user.setGender(1);
    //此时deleteFlag为空
    userinfo.addUserinfo(user);
}

此时代码报错了,我们可以从MyBatis打印的日志中看出SQL语句出现了多余的逗号。

此时就需要使用<trim>标签

<trim>标签

<trim>标签中有如下属性:

  • prefix:表示在整个语句块起始位置加上prefix的值作为前缀
  • suffix:表示在整个语句块结尾加上suffix的值作为后缀
  • prefixOverrides:如果整个语句块的前缀等于prefixOverrides的值,去掉prefixOverrides的值;
  • suffixOverrides:如果整个语句块的后缀等于suffixOverrides的值,去掉suffixOverrides的值。

我们利用<trim>标签来将上述SQL中结尾的 ‘,’ 去除

<insert id="addUserinfo">
    insert into userinfo 
    <trim prefix="(" suffix=")" suffixOverrides=",">
        id, username,
        <if test="gender != null">
            gender,
        </if>
        <if test="deleteFlag != null">
            delete_flag
        </if>
    </trim>
    values
    <trim prefix="(" suffix=");" suffixOverrides=",">    
        #{id},#{username},
        <if test="gender != null">
          #{gender},
        </if>
        <if test="deleteFlag != null">
            #{deleteFlag}
        </if>
    </trim>
</insert>

此时程序就可以正常执行了。

<where>标签

<where>标签一般应用于需要动态组装where条件的地方。

<where> 只会在子元素有内容的情况下才插入where子句,而且会自动去除子句的开头的AND或
OR。

例如:我们此时根据 id 和 gender 来查找数据。

数据库中的数据如下:

接口定义:

User selectUser(Integer id, Integer gender);

xml实现:

<select id="selectUser" resultType="com.example.Spring_demo.mySQL.User">
    select * from userinfo
    <where>
        <if test="id != null">
            id=#{id}
        </if>
    
        <if test="gender != null">
            and gender=#{gender}
        </if>

    </where>
    ;
</select>

JAVA测试代码

@Test
void selectUser() {
    System.out.println(userinfo.selectUser(1, 1));
}

从打印的结果和日志中我们可以看出结果正确。

如果 id 和 gender 都为 null

@Test
void selectUser() {
    System.out.println(userinfo.selectUser(null, null));
}

虽然程序报错了,可是并不是因为SQL错了而是因为接收的参数报错。

此时可以看出 where 被去掉了。 

此时如果 gender 为空

@Test
void selectUser() {
    System.out.println(userinfo.selectUser(1, null));
}

<where>标签并不能去除句末的 and 

<set>标签

<set>标签用于动态更新数据

用于 update 语句中动态的在SQL语句中插入 set 关键字,并会删掉额外的逗号。

例如:根据传入的id属性,修改 username 和 gender 中不为null的属性。

接口定义:

Integer upData(Integer id, String username, Integer gender);

xml代码实现:

<update id="upData">
    update userinfo  
    <set>
        <if test="username != null">
            username = #{username},
        </if>
        <if test="gender != null">
            gender = #{gender}
        </if>
    </set>
    where id = #{id};
</update>

JAVA测试代码

void upData() {
    //gender为空
    userinfo.upData(2, "xiaohong", null);
}


可以看出删掉了额外的逗号(前后都会删掉)。

<foreach>标签

该标签可以在对集合进行遍历时使用。

标签有如下属性:

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

例如:批量删除数据

接口定义:

Integer deleteUsers(List<Integer> ids);

xml代码实现:

<delete id="deleteUsers">
    delete from userinfo where id in
    <foreach collection="ids" item="id" open="(" close=");" separator=",">
        #{id}
    </foreach>
</delete>

注意:这两个地方的名称必须相同。

JAVA测试代码

@Test
void deleteUsers() {
    List<Integer> list = new ArrayList<>();
    list.add(1);
    list.add(2);
    userinfo.deleteUsers(list);
}

<include>和<SQL>标签

这两个标签配合使用可以实现对重复的代码片段进行抽取,将其通过 <sql> 标签封装到一个SQL片段,然后再通过<include> 标签进行引用。用来降低代码的冗余度。

  • <sql> :定义可重用的SQL片段
  • <include> :通过属性refid,指定包含的SQL片段

例如:我们可以抽取下面xml中的部分代码。

<delete id="deleteUsers">
    delete from userinfo where id in
    <foreach collection="ids" item="id" open="(" close=");" separator=",">
        #{id}
    </foreach>
</delete>
<sql id="aaa">
    delete from userinfo where id in
</sql>

<delete id="deleteUsers">
    <include refid="aaa"></include>
    <foreach collection="ids" item="id" open="(" close=");" separator=",">
        #{id}
    </foreach>
</delete>

 JAVA测试代码

@Test
void deleteUsers() {
    List<Integer> list = new ArrayList<>();
    list.add(1);
    list.add(2);
    userinfo.deleteUsers(list);
}

@注解的实现方式

注解的实现其实非常简单只需把xml标签中的SQL(包括标签),使用<script></script> 标签括起来就可以了。

例如下面的xml代码

<insert id="insertUserByCondition">
INSERT INTO userinfo (
username,
`password`,
age,
<if test="gender != null">
gender,
</if>
phone)
VALUES (
#{username},
#{age},
<if test="gender != null">
#{gender},
</if>
#{phone})
</insert>

注解的实现方法:

@Insert("<script>" +
    "INSERT INTO userinfo (username,`password`,age," +
    "<if test='gender!=null'>gender,</if>" +
    "phone)" +
    "VALUES(#{username},#{age}," +
    "<if test='gender!=null'>#{gender},</if>" +
    "#{phone})"+
    "</script>")
Integer insertUserByCondition(UserInfo userInfo);

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

二维差分---三维差分算法笔记

文章目录 一.二维差分构造差分二维数组二维差分算法状态dp求b[i][j]数组的二维前缀和图解 二.三维前缀和与差分三维前缀和图解:三维差分核心公式图解:模板题 一.二维差分 给定一个原二维数组a[i][j],若要给a[i][j]中以(x1,y1)和(x2,y2)为对角线的子矩阵中每个数都加上一个常数…

代码随想录|Day 14

Day 14 新年将至 一、理论学习 BFS 的使用场景总结&#xff1a;层序遍历、最短路径问题(https://leetcode.cn/problems/binary-tree-level-order-traversal/solutions/244853/bfs-de-shi-yong-chang-jing-zong-jie-ceng-xu-bian-l/) BFS 的应用一&#xff1a;层序遍历 BFS …

开发JSP应用程序

开发JSP应用程序 问题陈述 TecknoSoft Pvt Ltd.公司的首席技术官(CTO)John Barrett将创建一个应用程序的任务委托给了开发团队,该应用程序应在客户访问其账户详细信息前验证其客户ID和密码。客户ID应是数字形式。John希望如果所输入的客户ID或密码不正确,应向客户显示错误…

面试经典150题 -- 栈(总结)

总的链接 面试经典 150 题 - 学习计划 - 力扣&#xff08;LeetCode&#xff09;全球极客挚爱的技术成长平台 关于栈 -- stack 的学习链接 c的STL中的栈 -- stack-CSDN博客 20 . 有效的括号 这题直接用栈模拟就好了; 这里用一种取巧的方法 , 当遇见左括号&#xff0c;加入右…

MATLAB环境下基于同态滤波方法的医学图像增强

目前图像增强技术主要分为基于空间域和基于频率域两大方面&#xff0c;基于空间域图像增强的方法包括了直方图均衡化方法和 Retinex 方法等&#xff0c;基于频率域的方法包括同态滤波方法。其中直方图均衡化方法只是根据图像的灰度概率分布函数进行简单的全局拉伸&#xff0c;没…

containerd中文翻译系列(十九)cri插件

cri插件包含的内容比较多&#xff0c;阅读之前请深呼吸三次、三次、三次。 CRI 插件的架构 本小节介绍了 containerd 的 cri 插件的架构。 该插件是 Kubernetes 容器运行时接口&#xff08;CRI&#xff09; 的实现。Containerd与Kubelet在同一个节点上运行。containerd内部的…

修改SpringBoot中默认依赖版本

例如SpringBoot2.7.2中ElasticSearch版本是7.17.4 我希望把它变成7.6.1

IOS破解软件安装教程

对于很多iOS用户而言&#xff0c;获取软件的途径显得较为单一&#xff0c;必须通过App Store进行下载安装。 这样的限制&#xff0c;时常让人羡慕安卓系统那些自由下载各类版本软件的便捷。 心中不禁生出疑问&#xff1a;难道iOS世界里&#xff0c;就不存在所谓的“破解版”软件…

C++Linux网络编程day02:select模型

本文是我的学习笔记&#xff0c;学习路线跟随Github开源项目&#xff0c;链接地址&#xff1a;30dayMakeCppServer 文章目录 select模型fd_set结构体 timeval结构体文件描述符的就绪条件带外数据与普通数据socket的状态 select模型 select是Linux下的一个IO复用模型&#xff…

Java LinkedList 实现栈和队列

Java LinkedList 实现栈和队列 package com.zhong.collection;import java.util.LinkedList;public class LinkedListDemo {public static void main(String[] args) {// LinkedList 创建一个队列LinkedList<String> queue new LinkedList<>();// 进队System.out…

Linux中断编程

大家好&#xff0c;今天给大家介绍Linux中断编程&#xff0c;文章末尾附有分享大家一个资料包&#xff0c;差不多150多G。里面学习内容、面经、项目都比较新也比较全&#xff01;可进群免费领取。 Linux中断编程涉及到操作系统层面的中断处理机制&#xff0c;它是Linux内核与硬…

基于FPGA的图像最近邻插值算法verilog实现,包括tb测试文件和MATLAB辅助验证

目录 1.算法运行效果图预览 2.算法运行软件版本 3.部分核心程序 4.算法理论概述 5.算法完整程序工程 1.算法运行效果图预览 将FPGA数据导入matlab显示图片&#xff0c;效果如下&#xff1a; 2.算法运行软件版本 vivado2019.2&#xff0c;matlab2022a 3.部分核心程序 ti…

vue3 之 商城项目—详情页

整体认识 路由配置 准备组件模版 <script setup></script><template><div class"xtx-goods-page"><div class"container"><div class"bread-container"><el-breadcrumb separator">">&…

AI实景无人直播 矩阵系统

矩阵系统&#xff1a;重塑未来的组织与沟通在不断变化的世界中&#xff0c;我们需要的不仅是适应变化的能力&#xff0c;更需要预见未来的视角。矩阵系统&#xff0c;正是一个能够助力我们应对复杂环境、实现高效组织和沟通的工具。一、矩阵系统的核心价值矩阵系统&#xff0c;…

【05】C++ 内存管理

文章目录 &#x1f308; Ⅰ C 内存分布&#x1f308; Ⅱ C 内存管理方式1. new 和 delete 操作内置类型2. new 和 delete 操作自定义类型 &#x1f308; Ⅲ operator new 和 operator delete&#x1f308; Ⅳ new 和 delete 的实现原理1. 内置数据类型2. 自定义数据类型 &#…

Blazor SSR/WASM IDS/OIDC 单点登录授权实例1-建立和配置IDS身份验证服务

目录: OpenID 与 OAuth2 基础知识Blazor wasm Google 登录Blazor wasm Gitee 码云登录Blazor SSR/WASM IDS/OIDC 单点登录授权实例1-建立和配置IDS身份验证服务Blazor SSR/WASM IDS/OIDC 单点登录授权实例2-登录信息组件wasmBlazor SSR/WASM IDS/OIDC 单点登录授权实例3-服务端…

如何解锁屏幕破损的 iPhone

iPhone 15 是 Apple 最新、最出色的智能手机。它拥有时尚的设计、尖端的技术和众多功能&#xff0c;使其成为市场上最令人垂涎​​的设备之一。不幸的是&#xff0c;与所有智能手机一样&#xff0c;iPhone 14 容易发生可能导致屏幕破裂的事故和事故。破损的屏幕可能是毁灭性的&…

【机器学习】合成少数过采样技术 (SMOTE)处理不平衡数据(附代码)

1、简介 不平衡数据集是机器学习和人工智能中普遍存在的挑战。当一个类别中的样本数量明显超过另一类别时&#xff0c;机器学习模型往往会偏向大多数类别&#xff0c;从而导致性能不佳。 合成少数过采样技术 (SMOTE) 已成为解决数据不平衡问题的强大且广泛采用的解决方案。 …

2024刘谦春晚第二个扑克牌魔术

前言 就是刚才看春晚感觉这个很神奇&#xff0c;虽然第一个咱模仿不过来&#xff0c;第二个全国人民这么多人&#xff0c;包括全场观众都有成功&#xff0c;这肯定是不需要什么技术&#xff0c;那我觉得这个肯定就是数学了&#xff0c;于是我就胡乱分析一通。 正文 首先准备…

C语言:分支与循环

创造不易&#xff0c;友友们给个三连吧&#xff01;&#xff01; C语⾔是结构化的程序设计语⾔&#xff0c;这⾥的结构指的是顺序结构、选择结构、循环结构&#xff0c;C语⾔是能够实 现这三种结构的&#xff0c;其实我们如果仔细分析&#xff0c;我们⽇常所⻅的事情都可以拆分…