【Mybatis】Mybatis操作数据库详解

news2024/10/6 8:32:26

Mybatis操作数据库

  • 什么是Mybatis
  • Mybatis入门
    • 准备工作
      • 创建Springboot工程 建表 创建实体类
    • 配置数据库连接字符串
    • 编写持久层代码
    • 单元测试
  • Mybatis的基础操作
    • 打印日志
    • 参数传递
    • 增(insert)
      • 返回主键
    • 删(delete)
    • 改(update)
    • 查(select)
  • Mybatis XML配置文件
    • 配置连接字符串和Mybatis
    • 写持久层代码
      • 添加mapper接口
      • 添加UserInfoXMLMapper.xml
    • 增删改查操作
      • 增(insert)
      • 删(delete)
      • 改(update)
      • 查(select)
  • 其他查询操作
    • 多表查询
      • 准备表
      • 准备model
      • 查询
    • #{}和${}
      • #{}和${}使用
        • integer类型的参数
        • string类型的参数
      • #{}和${}的区别
      • 排序功能
      • like查询
  • 数据库连接池
    • 介绍
    • 使用
  • 动态sql
    • <if>标签
    • <trim>
    • <where>标签
    • <set>标签
    • <foreach>标签
    • <incloud>标签

什么是Mybatis

MyBatis(前身为iBATIS)是一种Java持久层框架,用于简化数据库访问的开发。它提供了一种将SQL语句与Java代码解耦的方式,使得数据库操作更加灵活和易于维护。

MyBatis的核心思想是通过XML或注解配置SQL映射关系,将SQL语句与Java方法进行关联。开发人员只需定义SQL语句,并将其映射到相应的Java方法上,MyBatis会自动执行SQL并将结果映射到Java对象中。

以下是MyBatis的一些主要特点:

  1. 简化数据库操作: MyBatis提供了简洁的API和灵活的配置方式,使得数据库操作变得更加简单和直观。

  2. 强大的SQL支持: MyBatis支持复杂的SQL语句,包括动态SQL、参数映射、嵌套查询等,可以满足各种数据库操作的需求。

  3. 性能优化: MyBatis具有良好的性能,可以通过缓存、批量操作等手段提升数据库操作效率。

  4. 与现有代码集成: MyBatis不需要引入复杂的对象关系映射(ORM),可以与现有的Java代码和数据库结构无缝集成。

  5. 可扩展性: MyBatis允许开发人员编写自定义的类型处理器、插件等,以满足特定的需求。

Mybatis入门

Mybatis操作数据库的步骤

  1. 准备⼯作(创建springboot⼯程、数据库表准备、实体类)
  2. 引⼊Mybatis的相关依赖,配置Mybatis(数据库连接信息)
  3. 编写SQL语句(注解/XML)
  4. 测试

准备工作

创建Springboot工程 建表 创建实体类

在这里插入图片描述
建表

-- 创建数据库
DROP DATABASE IF EXISTS mybatis_test;
CREATE DATABASE mybatis_test DEFAULT CHARACTER SET utf8mb4;
-- 使⽤数据数据
USE mybatis_test;
-- 创建表[⽤⼾表]
DROP TABLE IF EXISTS userinfo;
CREATE TABLE `userinfo` (
                            `id` INT ( 11 ) NOT NULL AUTO_INCREMENT,
                            `username` VARCHAR ( 127 ) NOT NULL,
                            `password` VARCHAR ( 127 ) NOT NULL,
                            `age` TINYINT ( 4 ) NOT NULL,
                            `gender` TINYINT ( 4 ) DEFAULT '0' COMMENT '1-男 2-⼥ 0-默认',
                            `phone` VARCHAR ( 15 ) DEFAULT NULL,
                            `delete_flag` TINYINT ( 4 ) DEFAULT 0 COMMENT '0-正常, 1-删除',
                            `create_time` DATETIME DEFAULT now(),
                            `update_time` DATETIME DEFAULT now(),
                            PRIMARY KEY ( `id` )
) ENGINE = INNODB DEFAULT CHARSET = utf8mb4;
-- 添加⽤⼾信息
INSERT INTO mybatis_test.userinfo ( username, `password`, age, gender, phone )
VALUES ( 'admin', 'admin', 18, 1, '18612340001' );
INSERT INTO mybatis_test.userinfo ( username, `password`, age, gender, phone )
VALUES ( 'zhangsan', 'zhangsan', 18, 1, '18612340002' );
INSERT INTO mybatis_test.userinfo ( username, `password`, age, gender, phone )
VALUES ( 'lisi', 'lisi', 18, 1, '18612340003' );
INSERT INTO mybatis_test.userinfo ( username, `password`, age, gender, phone )
VALUES ( 'wangwu', 'wangwu', 18, 1, '18612340004' );

创建实体类

import lombok.Data;
import java.util.Date;

@Data
public class UserInfo {
    private Integer id;
    private String username;
    private String password;
    private Integer age;
    private Integer gender;
    private String phone;
    private Integer deleteFlag;
    private Date createTime;
    private Date updateTime;
}

配置数据库连接字符串

Mybatis要连接数据库 需要配置相关参数

  1. Mysql驱动类
  2. 登录名
  3. 密码
  4. 数据库连接字符串

配置application.yml文件

spring:
  datasource:
    url: jdbc:mysql://127.0.0.1:3306/mybatis_test?characterEncoding=utf8&useSSL=false
    username: root
    password: 111111
    driver-class-name: com.mysql.cj.jdbc.Driver

编写持久层代码

import com.example.mybatisdemo.model.UserInfo;
import org.apache.ibatis.annotations.*;

import java.util.List;

//@Mapper注解; 表示是mybatis中的mapper接口
//程序运行时 框架会自动生成接口的实现类对象 并交给springioc容器管理
@Mapper
public interface UserInfoMapper {
    //查询所有用户
    @Select("select * from userinfo")
    List<UserInfo> queryAllUser();
}

单元测试

import java.util.List;

import static org.junit.jupiter.api.Assertions.*;
//添加springboot注解 该测试类在运行时 就会自动加载spring的运行环境
@SpringBootTest
@Slf4j
class UserInfoMapperTest {
    //注入要测试的类
    @Autowired
    private UserInfoMapper userInfoMapper;
    @Test
    void queryAllUser() {
        List<UserInfo> userInfoList = userInfoMapper.queryAllUser();
        System.out.println(userInfoList);
    }
}

Mybatis的基础操作

打印日志

在Mybatis当中我们可以借助⽇志, 查看到sql语句的执⾏、执⾏传递的参数以及执⾏结果
在配置⽂件中进⾏配置即可

mybatis:
  configuration: # 配置打印 MyBatis日志
    log-impl: org.apache.ibatis.logging.stdout.StdOutImpl

此时就可以看到sql执行内容 传递参数 执行结果
在这里插入图片描述

参数传递

需求:查找id = 4 的用户对应的SQL就是: select * from userinfo where id=4

但是这样的话, 只能查找id=4 的数据, 所以SQL语句中的id值不能写成固定数值,需要变为动态的数值
解决⽅案:在queryById⽅法中添加⼀个参数(id),将⽅法中的参数,传给SQL语句
使⽤ #{} 的⽅式获取⽅法中的参数

@Select("select username, `password`, age, gender, phone from userinfo where id=#{id}")
UserInfo queryById(Integer id);

如果mapper接⼝⽅法形参只有⼀个普通类型的参数,#{…} ⾥⾯的属性名可以随便写,如:#{id}、#{value}。建议和参数名保持⼀致

测试用例

void queryUserById() {
        List<UserInfo> userInfo = userInfoMapper.queryUserById(4);
        System.out.println(userInfo);
    }

运行结果
在这里插入图片描述

增(insert)

sql语句

@Insert("insert into userinfo (username,password,age,gender,phone) " +
            "values(#{username},#{password},#{age},#{gender},#{phone})")
    Integer insert(UserInfo userInfo);
            //把sql中的常量替换为动态的参数

测试代码
直接使用UserInfo对象的属性名来获取参数

@Test
    void insert() {
        UserInfo userInfo = new UserInfo();
        userInfo.setUsername("zhangliu");
        userInfo.setPassword("123456789");
        userInfo.setAge(18);
        userInfo.setGender(1);
        userInfo.setPhone("15968456325");
        Integer result = userInfoMapper.insert(userInfo);
        System.out.println("添加数据条数:"+result + ", 主键id:"+userInfo.getId());
    }

如果设置了 @Param 属性, #{…} 需要使⽤ 参数.属性 来获取

@Insert("insert into userinfo (username,password,age,gender,phone) " +
            "values(#{userinfo.username},#{userinfo.password},#{userinfo.age},#{userinfo.gender},#{userinfo.phone})")
    Integer insert2(@Param("userinfo") UserInfo userInfo);

返回主键

Insert 语句默认返回的是 受影响的⾏数

但有些情况下, 数据插⼊之后, 还需要有后续的关联操作, 需要获取到新插⼊数据的id

如果想要拿到⾃增id, 需要在Mapper接⼝的⽅法上添加⼀个Options的注解

@Options(useGeneratedKeys = true, keyProperty = "id")
    @Insert("insert into userinfo (username,password,age,gender,phone) " +
            "values(#{username},#{password},#{age},#{gender},#{phone})")
    Integer insert(UserInfo userInfo);

useGeneratedKeys:这会令 MyBatis 使⽤ JDBC 的 getGeneratedKeys ⽅法来取出由数据库内部⽣成的主键(⽐如:像 MySQL 和 SQL Server 这样的关系型数据库管理系统的⾃动递增字段),默认值:false
keyProperty:指定能够唯⼀识别对象的属性,MyBatis 会使⽤ getGeneratedKeys 的返回值或insert 语句的 selectKey ⼦元素设置它的值,默认值:未设置(unset)

测试数据

@Test
    void insert() {
        UserInfo userInfo = new UserInfo();
        userInfo.setUsername("zhangliu");
        userInfo.setPassword("123456789");
        userInfo.setAge(18);
        userInfo.setGender(1);
        userInfo.setPhone("15968456325");
        Integer result = userInfoMapper.insert(userInfo);
        System.out.println("添加数据条数:"+result + ", 主键id:"+userInfo.getId());
    }

在这里插入图片描述

删(delete)

sql

@Delete("delete from userinfo where id = #{id}")
        //根据id删除
    Integer delete(Integer id);

测试代码

@Test
    void delete() {
        Integer result = userInfoMapper.delete(5);
    }

改(update)

sql

@Update("update userinfo set username=#{username} where id=#{id}")
    Integer update(UserInfo userInfo);
}

测试代码

@Test
    void update() {
        UserInfo userInfo = new UserInfo();
        userInfo.setUsername("wuqi");
        userInfo.setId(1);
        Integer result= userInfoMapper.update(userInfo);
        if (result>0){
            log.info("数据修改成功");
        }
        Integer update = userInfoMapper.update(userInfo);
    }

查(select)

@Select("select * from userinfo where id = #{id}")
    List<UserInfo> queryUserById(Integer id);

测试代码

@Test
    void queryAllUser() {
        List<UserInfo> userInfoList = userInfoMapper.queryAllUser();
        System.out.println(userInfoList);
    }

Mybatis XML配置文件

Mybatis的开发有两种⽅式:

  1. 注解
  2. XML
    上⾯学习了注解的⽅式, 接下来我们学习XML的⽅式

使⽤Mybatis的注解⽅式,主要是来完成⼀些简单的增删改查功能. 如果需要实现复杂的SQL功能,建议使⽤XML来配置映射语句,也就是将SQL语句写在XML配置⽂件中.
MyBatis XML的⽅式需要以下两步:

  1. 配置数据库连接字符串和MyBatis
  2. 写持久层代码

配置连接字符串和Mybatis

此步骤需要进⾏两项设置,数据库连接字符串设置和 MyBatis 的 XML ⽂件配置。
如果是application.yml⽂件, 配置内容如下:

# 数据库连接配置
spring:
 datasource:
 url: jdbc:mysql://127.0.0.1:3306/mybatis_test?characterEncoding=utf8&useSSL=
 username: root
 password: root
 driver-class-name: com.mysql.cj.jdbc.Driver
# 配置 mybatis xml 的⽂件路径,在 resources/mapper 创建所有表的 xml ⽂件
mybatis:
 mapper-locations: classpath:mapper/**Mapper.xml

写持久层代码

持久层代码分两部分

  1. ⽅法定义 Interface
  2. ⽅法实现: XXX.xml

添加mapper接口

package com.example.mybatisdemo.mapper;

import com.example.mybatisdemo.model.UserInfo;
import org.apache.ibatis.annotations.Mapper;

import java.util.List;

@Mapper
public interface UserInfoXMLMapper {
	//查
    List<UserInfo> queryAllUser();

    //增
    Integer insertUser(UserInfo userInfo);

    //删
    Integer deleteUser(Integer id);

    //改
    Integer updateUser(UserInfo userInfo);
}

添加UserInfoXMLMapper.xml

数据持久成的实现,MyBatis 的固定 xml 格式:

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.example.mybatisdemo.mapper.UserInfoXMLMapper">
<!--mapper标签 需要指定namespace属性,表示命名空间,值为mapper接口的全限定名,包括全包名,类名 -->

</mapper>

增删改查操作

增(insert)

UserInfoMapper接⼝:

Integer insertUser(UserInfo userInfo);

xml

<!--要返回主键 useGeneratedKeys="true-->
<!--主键的值赋给id keyProperty="id"-->
    <insert id="insertUser" useGeneratedKeys="true" keyProperty="id">
        insert into userinfo (username,password,age,gender,phone)
        values(#{username},#{password},#{age},#{gender},#{phone})
    </insert>

删(delete)

mapper接口

Integer deleteUser(Integer id);

xml

<delete id="deleteUser">
        delete from userinfo where id = #{id}
</delete>

改(update)

mapper接口

Integer updateUser(UserInfo userInfo);

xml

<update id="updateUser">
        update userinfo set username = #{username} where id = #{id}
</update>

查(select)

mapper接口

List<UserInfo> queryAllUser();
<select id="queryAllUser" resultType="com.example.mybatisdemo.model.UserInfo">
        select * from userinfo
    </select>

其他查询操作

多表查询

准备表

DROP TABLE IF EXISTS articleinfo;

CREATE TABLE articleinfo (
                             id INT PRIMARY KEY auto_increment,
                             title VARCHAR ( 100 ) NOT NULL,
                             content TEXT NOT NULL,
                             uid INT NOT NULL,
                             delete_flag TINYINT ( 4 ) DEFAULT 0 COMMENT '0-正常, 1-删除',
                             create_time DATETIME DEFAULT now(),
                             update_time DATETIME DEFAULT now()
) DEFAULT charset 'utf8mb4';

INSERT INTO articleinfo ( title, content, uid ) VALUES ( 'Java', 'Java正⽂', 1 );

准备model

package com.example.mybatisdemo.model;

import lombok.Data;

import java.util.Date;

@Data
public class ArticleInfo {
    private Integer id;
    private String title;
    private String content;
    private Integer uid;
    private Integer deleteFlag;
    private Date createTime;
    private Date updateTime;
}

查询

要求 根据uid查询作者的名称等相关信息

SELECT
 ta.id,
 ta.title,
 ta.content,
 ta.uid,
 tb.username,
 tb.age,
 tb.gender 
FROM
 articleinfo ta
 LEFT JOIN userinfo tb ON ta.uid = tb.id 
WHERE
 ta.id =1

先补充查询结果的实体类

public class ArticleInfo {
 private Integer id;
 private String title;
 private String content;
 private Integer uid;
 private Integer deleteFlag;
 private Date createTime;
 private Date updateTime;
 //⽤⼾相关信息
 private String username;
 private Integer age;
 private Integer gender;
}

mapper接口

@Mapper
public interface ArticleInfoMapper {
    //多表查询
    @Select("select ta.*, tb.username,tb.age,tb.gender from articleinfo ta" +
            " LEFT JOIN userinfo tb on ta.uid = tb.id" +
            " where ta.id=#{id}")
    ArticleInfo queryUserById(Integer id);

}

#{}和${}

#{}和${}使用

integer类型的参数

在这里插入图片描述
我们发现输出的sql语句 参数并没有直接在后面拼接 id的值是使用?进行占位 这种sql我们成为预编译sql

此时把#{}改成${} 再观察打印的日志
在这里插入图片描述
此时我们输入的参数是直接拼接在sql中了

string类型的参数
@Select("select * from userinfo where username = #{username}")
    List<UserInfo> queryUserByName(String username);

在这里插入图片描述
我们再把#{}修改为${}
在这里插入图片描述
此时我们发现 这次的参数直接拼接在sql中 但是我们以字符串为参数时,需要添加引号,但是使用 ${} 不会拼接引号 导致程序报错
此时我们需要手动添加引号
在这里插入图片描述

#{}和${}的区别

在MyBatis中,#{}和${}都是用于在SQL语句中进行参数的传递,但它们之间有一些重要的区别。

#{}用于预编译参数,MyBatis在将SQL语句发送到数据库之前,会使用PreparedStatement参数化查询的方式来处理#{}中的内容,这样可以有效防止SQL注入攻击,并且能够正确地处理特殊字符转义。因此,建议在编写SQL语句时使用#{}来引用参数。

${}则是直接进行字符串替换,不会进行预编译,而是将其中的内容直接拼接到sql语句中。这种方式可能会存在sql注入的风险,因此不建议在编写sql语句时使用则是直接进行字符串替换,不会进行预编译,而是将其中的内容直接拼接到SQL语句中。这种方式可能会存在SQL注入的风险,因此不建议在编写SQL语句时使用{}来引用参数,除非你非常清楚自己在做什么并且能够确保参数的安全性。

因此,总的来说,推荐在MyBatis中使用#{}来引用参数,以确保SQL的安全性和可读性。

排序功能

从上⾯的例⼦中, 可以得出结论: ${} 会有SQL注⼊的⻛险, 所以我们尽量使⽤#{}完成查询
既然如此, 是不是 ${} 就没有存在的必要性了呢?
当然不是.

比如我们要实现一个排序功能
mapper

@Select("select * from userinfo order by id ${sort}")
    List<UserInfo> queryAllUserBySort(String sort);

测试代码

 @Test
    void queryAllUserBySort() {
        List<UserInfo> userInfoList = userInfoMapper.queryAllUserBySort("desc");
        System.out.println(userInfoList);

    }

在这里插入图片描述
我们可以看到我们完成了对id的降序排序

此时我们将${}改成#{}
在这里插入图片描述
此时我们发现sql报错了

此处报错的原因就是 在使用#{}时 给desc自动加上了引号 但是实际上此处并不需要在此处加引号 导致了报错
#{} 会根据参数类型判断是否拼接引号 ''如果参数类型为String, 就会加上 引号

除此之外, 还有表名作为参数时, 也只能使⽤ ${}

like查询

like 使⽤ #{} 报错

mapper

 @Select("select * from userinfo where username like '%#{key}%'")
    List<UserInfo> queryAllUserByLike(String key);

测试代码

@Test
    void queryAllUserByLike() {
        List<UserInfo> userInfoList = userInfoMapper.queryAllUserByLike("x");
        System.out.println(userInfoList);
    }

在这里插入图片描述

我们发现此时还是由于引号的问题 导致sql语句不能够正常表达

此时我们可以使用KaTeX parse error: Expected 'EOF', got '#' at position 6: {}替换 #̲{} , 但是此时又引入了sq…{}

此时我们的解决方法 可以使用mysql内置函数concat()来处理
在这里插入图片描述
此时就可以解决sql注入问题 还能够完成模糊查询的需求

数据库连接池

在上⾯Mybatis的讲解中, 我们使⽤了数据库连接池技术, 避免频繁的创建连接, 销毁连接下⾯我们来了解下数据库连接池

介绍

数据库连接池负责分配、管理和释放数据库连接,它允许应⽤程序重复使⽤⼀个现有的数据库连接,⽽不是再重新建⽴⼀个.

有使⽤数据库连接池的情况: 每次执⾏SQL语句, 要先创建⼀个新的连接对象, 然后执⾏SQL语句, SQL语句执⾏完, 再关闭连接对象释放资源. 这种重复的创建连接, 销毁连接⽐较消耗资源
使⽤数据库连接池的情况: 程序启动时, 会在数据库连接池中创建⼀定数量的Connection对象, 当客⼾请求数据库连接池, 会从数据库连接池中获取Connection对象, 然后执⾏SQL, SQL语句执⾏完, 再把Connection归还给连接池

使用

常⻅的数据库连接池:

  • C3P0
  • DBCP
  • Druid
  • Hikari

⽬前⽐较流⾏的是 Hikari, Druid

  1. Hikari : SpringBoot默认使⽤的数据库连接池
    在这里插入图片描述
  2. Druid
    如果我们想把默认的数据库连接池切换为Druid数据库连接池, 只需要引⼊相关依赖即可
<dependency>
	 <groupId>com.alibaba</groupId>
	 <artifactId>druid-spring-boot-starter</artifactId>
	 <version>1.1.17</version>
</dependency>

在这里插入图片描述

动态sql

动态 SQL 是Mybatis的强⼤特性之⼀,能够完成不同条件下不同的 sql 拼接

标签

在注册用户的时候 可能会有这样一个问题 在注册的过程中 会出现必填字段和非必填字段,如果再添加用户的时候有不确定的字段传入,程序该如何实现呢?

此时就应该使用动态标签来判断了 ,例如添加的时候gender为非必填字段

xml方式实现

    <insert id="insertUserByCondition">
        insert into userinfo(
                             `username`,
                             `password`,
                             `age`,
                             <if test="gender != null">
                                 gender,
                             </if>
                             phone)
        values (
                #{username},
                #{password},
                #{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);

在这里插入图片描述
当gender不填写时,此时就没有gender

之前的插⼊⽤⼾功能,只是有⼀个 gender 字段可能是选填项,如果有多个字段,⼀般考虑使⽤标签结合标签,对多个字段都采取动态⽣成的⽅式。

标签中有如下属性:

  • prefix:表⽰整个语句块,以prefix的值作为前缀
  • suffix:表⽰整个语句块,以suffix的值作为后缀
  • prefixOverrides:表⽰整个语句块要去除掉的前缀
  • suffixOverrides:表⽰整个语句块要去除掉的后缀
    <insert id="insertUserByCondition">
        insert into userinfo
        <trim prefix="(" suffix=")" suffixOverrides=",">
            <if test="username != null">
                `username`,
            </if>
            <if test="password != null">
                `password`,
            </if>
            <if test="age != null">
                `age`,
            </if>
            <if test="gender != null">
                `gender`,
            </if>
            <if test="phone != null">
                `phone`
            </if>
        </trim>
        values
        <trim prefix="(" suffix=")" suffixOverrides=",">
            <if test="username != null">
                #{username},
            </if>
            <if test="password != null">
                #{password},
            </if>
            <if test="age != null">
                #{age},
            </if>
            <if test="gender != null">
                #{gender},
            </if>
            <if test="phone != null">
                #{phone}
            </if>
        </trim>
    </insert>

在以上 sql 动态解析时,会将第⼀个 部分做如下处理:
• 基于 prefix 配置,开始部分加上 (
• 基于 suffix 配置,结束部分加上 )
• 多个 组织的语句都以 , 结尾,在最后拼接好的字符串还会以 , 结尾,会基于suffixOverrides 配置去掉最后⼀个,

标签

需求: 传⼊的⽤⼾对象,根据属性做where条件查询,⽤⼾对象中属性不为 null 的,都为查询条件. 如username 为 “a”,则查询条件为 where username=“a”

sql

SELECT
 * 
FROM
 userinfo 
WHERE
 age = 18
 AND gender = 1
 AND delete_flag =0

xml

<select id="queryByCondition">
        select *
        from userinfo
        <where>
            <if test="age != null">
                and age = #{age}
            </if>
            <if test="gender != null">
                and gender = #{gender}
            </if>
            <if test="deleteFlag != null">
                and delete_flag = #{deleteFlag}
            </if>
        </where>
    </select>

标签

需求: 根据传⼊的⽤⼾对象属性来更新⽤⼾数据,可以使⽤标签来指定动态内容.

xml

<update id="updateUserByCondition">
        update userinfo
        <set>
            <if test="username != null">
                username = #{username},
            </if>
            <if test="age != null">
                age = #{age},
            </if>
            <if test="deleteFlag != null">
                delete_flag = #{deleteFlag},
            </if>
        </set>
        where id = #{id}
    </update>

mapper接口

Integer updateUserByCondition(UserInfo userInfo);

测试代码

@Test
    void updateUserByCondition() {
        UserInfo userInfo = new UserInfo();
        userInfo.setId(1);
        userInfo.setUsername("zhangsan");
        Integer integer = userInfoXMLMapper.updateUserByCondition(userInfo);

    }

标签

对集合进⾏遍历时可以使⽤该标签。标签有如下属性:
• collection:绑定⽅法参数中的集合,如 List,Set,Map或数组对象
• item:遍历时的每⼀个对象
• open:语句块开头的字符串
• close:语句块结束的字符串
• separator:每次遍历之间间隔的字符串
需求: 根据多个userid, 删除⽤⼾数据

xml

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

接口

void deleteByIds(List<Integer> ids);

测试代码

@Test
    void deleteByIds() {
        userInfoXMLMapper.deleteByIds(Arrays.asList(1,2,3,4));
    }

标签

问题分析:
在xml映射⽂件中配置的SQL,有时可能会存在很多重复的⽚段,此时就会存在很多冗余的代码

我们可以对重复的代码⽚段进⾏抽取,将其通过 标签封装到⼀个SQL⽚段,然后再通过 标签进⾏引⽤

• :定义可重⽤的SQL⽚段
• :通过属性refid,指定包含的SQL⽚段

<sql id="allColumn">
 id, username, age, gender, phone, delete_flag, create_time, update_time
</sql>

通过 标签在原来抽取的地⽅进⾏引⽤。操作如下:

<select id="queryAllUser" resultMap="BaseMap">
 select
 <include refid="allColumn"></include>
 from userinfo
</select>

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

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

相关文章

Jenkins CI/CD

1、 Jenkins CI/CD 流程图 说明&#xff1a;这张图稍微更形象一点&#xff0c;上线之前先把代码git到版本仓库&#xff0c;然后通过Jenkins 如Java项目通过maven去构建&#xff0c;这是在非容器之前&#xff0c;典型的自动化的一个版本上线流程。那它有哪些问题呢&#xff1f; …

Docker Swarm总结+基础、集群搭建维护、安全以及集群容灾(1/3)

博主介绍&#xff1a;Java领域优质创作者,博客之星城市赛道TOP20、专注于前端流行技术框架、Java后端技术领域、项目实战运维以及GIS地理信息领域。 &#x1f345;文末获取源码下载地址&#x1f345; &#x1f447;&#x1f3fb; 精彩专栏推荐订阅&#x1f447;&#x1f3fb;…

基于C#实现外排序

一、N 路归并排序 1.1、概序 我们知道算法中有一种叫做分治思想&#xff0c;一个大问题我们可以采取分而治之&#xff0c;各个突破&#xff0c;当子问题解决了&#xff0c;大问题也就 KO 了&#xff0c;还有一点我们知道内排序的归并排序是采用二路归并的&#xff0c;因为分治…

【Redis基础】Redis安装及管理详细教程

✅作者简介&#xff1a;大家好&#xff0c;我是小杨 &#x1f4c3;个人主页&#xff1a;「小杨」的csdn博客 &#x1f433;希望大家多多支持&#x1f970;一起进步呀&#xff01; 1&#xff0c;UBuntu安装Redis 1&#xff0c;使用su命令切换到root用户 su2&#xff0c;使用se…

windows运行Pangolin应用填坑心得——如何在window应用轻量级opengl软件Pangolin库显示3D界面及窗口

目录 0、前言1、最有效的安装打开方式准备工作安装git安装vcpkg&#xff08;1&#xff09;下载&#xff08;2&#xff09;安装&#xff08;3&#xff09;集成至vs 安装cmake 安装pangolin 2、应用实例c工程&#xff08;1&#xff09;vs创建新工程&#xff08;2&#xff09;新工…

盘点60个Python爬虫源码Python爱好者不容错过

盘点60个Python爬虫源码Python爱好者不容错过 爬虫&#xff08;Spider&#xff09; 学习知识费力气&#xff0c;收集整理更不易。 知识付费甚欢喜&#xff0c;为咱码农谋福利。 链接&#xff1a;https://pan.baidu.com/s/1JWrDgl46_ammprQaJiKqaQ?pwd8888 提取码&#xff…

Mysql并发时常见的死锁及解决方法

使用数据库时&#xff0c;有时会出现死锁。对于实际应用来说&#xff0c;就是出现系统卡顿。 死锁是指两个或两个以上的事务在执行过程中&#xff0c;因争夺资源而造成的一种互相等待的现象。就是所谓的锁资源请求产生了回路现象&#xff0c;即死循环&#xff0c;此时称系统处于…

2023 年 认证杯 小美赛 国际大学生数学建模挑战赛 |数学建模完整代码+建模过程全解全析

当大家面临着复杂的数学建模问题时&#xff0c;你是否曾经感到茫然无措&#xff1f;作为2022年美国大学生数学建模比赛的O奖得主&#xff0c;我为大家提供了一套优秀的解题思路&#xff0c;让你轻松应对各种难题。 cs数模团队在认证杯 小美赛前为大家提供了许多资料的内容呀&am…

数字图像处理(实践篇)一 将图像中的指定目标用bBox框起来吧!

目录 一 实现方法 二 涉及的OpenCV函数 三 代码 四 效果图 一 实现方法 ①利用OTSU方法将前景与背景分割。 ②使用连通区域分析可以将具有相同像素值且位置相邻的前景像素点组成的图像区域识别。 ③画bbox。 ④显示结果。 二 涉及的OpenCV函数 ① OpenCV提供了cv2.th…

【小技巧】复制一个模块到你的工程(学习阶段很实用)

问题描述&#xff1a; 当我们学习Springboot时&#xff0c;需要创建大量的模块&#xff0c;而这些模块的许多代码都是重复的&#xff0c;只有模块名等相关的信息不一样&#xff0c;现在就教你如何快速创建一个模块。 应用场景&#xff1a; ①进入项目文件夹&#xff1a; ②复…

Android : 模仿西瓜视频_主页界面_简单应用

示例图&#xff1a; MainActivity.java package com.example.xihuashipingapp;import androidx.appcompat.app.AppCompatActivity;import android.os.Bundle; import android.util.DisplayMetrics; import android.view.View; import android.widget.Button; import android.…

计算机组成原理(计算机系统概述)

目录 一. 计算机的发展二. 计算机硬件的基本组成2.1 早期冯诺依曼机2.2 现代计算机的结构 三. 各硬件的工作原理3.1 主存储器的基本组成3.2 运算器的基本组成3.3 控制器的基本组成 四. 计算机的工作过程 \quad 一. 计算机的发展 计算机系统 硬件 软件 #mermaid-svg-gp2AsYELE…

如何搭建zerotier服务器组网实现内网穿透

小白花了四天的下班时间终于把zerotier网络调通&#xff0c;此刻坐在桌前舒畅地喝口茶&#xff5e;&#xff5e; 下面来详细记录下这几天踩的坑&#xff1a; 起因就在于一直在iPad上用向日葵连接公司电脑的我觉得向日葵的界面用的实在难受&#xff0c;vs code操作十分不灵光&…

Windows核心编程 线程

目录 线程概述 进程与线程的关系 线程调度原理 单核与多核的线程处理方式 多线程 线程相关API 线程分配 线程切换时 线程状态 线程退出 线程退出时做的事&#xff08;正常退出情况&#xff09; 线程概述 程序磁盘上的一个可执行文件&#xff08;由指令和数据等组成…

Flash Attention:高效注意力机制的突破与应用

注意力机制彻底改变了自然语言处理和深度学习领域。它们允许模型在执行机器翻译、语言生成等任务时专注于输入数据的相关部分。 在这篇博客[1]中&#xff0c;我们将深入研究被称为“Flash Attention”的注意力机制的突破性进展。我们将探讨它是什么、它是如何工作的&#xff0c…

赋值,浅拷贝,深拷贝

1.前置知识 数据分为基本类型(String, Number, Boolean, Null, Undefined&#xff0c;Symbol)和引用类型(Object)基本类型&#xff1a;直接存储在栈内存中的数据引用类型&#xff1a;指向改数据的指针变量存储在栈内存中&#xff0c;真实的数据存储在堆内存中引用类型在栈内存…

SpectralGPT: Spectral Foundation Model 论文翻译1

遥感领域的通用大模型 2023.11.13在CVPR发表 原文地址&#xff1a;[2311.07113] SpectralGPT: Spectral Foundation Model (arxiv.org) 摘要 ​ 基础模型最近引起了人们的极大关注&#xff0c;因为它有可能以一种自我监督的方式彻底改变视觉表征学习领域。虽然大多数基础模型…

河南省第一届职业技能大赛网络安全项目试题

河南省第一届职业技能大赛 网络安全项目试题 一、竞赛时间 总计&#xff1a;420分钟 竞赛阶段 竞赛阶段 任务阶段 竞赛任务 竞赛时间 分值 A模块 A-1 登录安全加固 240分钟 200分 A-2 Web安全加固&#xff08;Web&#xff09; A-3 流量完整性保护与事件监控&a…

Openwrt 包管理系统介绍

Openwrt 包管理系统介绍 1. OpenWrt简介1.1 主要特点1.2 开源嵌入式操作系统1.2.1 嵌入式系统概念1.2.2 嵌入式系统分类1.2.3 嵌入式系统——安卓1.2.4 嵌入式系统的对比 2 OpenWrt包管理系统2.1 工作原理2.2 OPKG命令2.2.1 命令用法2.2.2 软件包的管理2.2.3 查询信息2.2.4 选项…

ubuntu 编译linux webrtc库

ubuntu 编译linux webrtc库 安装依赖 sudo apt-get update sudo apt-get install build-essential libssl-dev libasound2-dev libpulse-dev libjpeg-dev libxv-dev libgtk-3-dev libxtst-dev libwebp-dev sudo apt-get install libglib2.0-dev sudo apt-get update 报错时出…