Mybatis学习笔记注解/xml映射/动态SQL%%%Mybatis教程

news2024/11/27 8:39:03

介绍

  • Mybatis 是一款优秀的持久层框架,用于简化 JDBC 的开发

MyBatis中文网

Mybatis 入门

快速入门

  • 步骤
  1. 创建 SpringBoot 工程、数据库表 user、实体类 User
  2. 引入 Mybatis 相关依赖,配置 Mybatis(数据库连接信息)
  3. 编写 SQL 语句(注解/XML)

项目创建

image.png
image.png
创建的项目的 pom.xml 如下:

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>3.1.4</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>
    <groupId>com.example</groupId>
    <artifactId>demoMybatis</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <name>demoMybatis</name>
    <description>demoMybatis</description>
    <properties>
        <java.version>17</java.version>
    </properties>
    <dependencies>
        <dependency>
            <groupId>org.mybatis.spring.boot</groupId>
            <artifactId>mybatis-spring-boot-starter</artifactId>
            <version>3.0.2</version>
        </dependency>

        <dependency>
            <groupId>com.mysql</groupId>
            <artifactId>mysql-connector-j</artifactId>
            <scope>runtime</scope>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
        <dependency>
            <groupId>org.mybatis.spring.boot</groupId>
            <artifactId>mybatis-spring-boot-starter-test</artifactId>
            <version>3.0.2</version>
            <scope>test</scope>
        </dependency>
    </dependencies>

    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>
    </build>

</project>

引入了这三个依赖:
image.png
image.png

数据库表格创建

image.png
代码如下:

CREATE DATABASE mybatis;
USE mybatis;

CREATE TABLE USER(
    id INT UNSIGNED PRIMARY KEY AUTO_INCREMENT COMMENT 'ID',
    NAME VARCHAR(100) COMMENT '姓名',
    age TINYINT UNSIGNED COMMENT '年龄',
    gender TINYINT UNSIGNED COMMENT '性别, 1:男, 2:女',
    phone VARCHAR(11) COMMENT '手机号'
) COMMENT '用户表';

INSERT INTO USER(id, NAME, age, gender, phone) VALUES (NULL,'白眉鹰王',55,'1','18800000000');
INSERT INTO USER(id, NAME, age, gender, phone) VALUES (NULL,'金毛狮王',45,'1','18800000001');
INSERT INTO USER(id, NAME, age, gender, phone) VALUES (NULL,'青翼蝠王',38,'1','18800000002');
INSERT INTO USER(id, NAME, age, gender, phone) VALUES (NULL,'紫衫龙王',42,'2','18800000003');
INSERT INTO USER(id, NAME, age, gender, phone) VALUES (NULL,'光明左使',37,'1','18800000004');
INSERT INTO USER(id, NAME, age, gender, phone) VALUES (NULL,'光明右使',48,'1','18800000005');

创建 User 实体类

image.png
实体类 User 中的属性与数据库表格中的字段是一一对应的
在实体类属性定义的时候使用相关数据类型的包装类型
再创建有参无参构造、getter/setter 方法以及 toString 方法

package com.example.pojo;

public class User {

    /*
    实体类 User 中的属性与数据库表格中的字段是一一对应的
    在实体类属性定义的时候使用相关数据类型的包装类型
     */
    private Integer id;
    private String name;
    private Short age;
    private Short gender;

    //生成getter和setter方法和toString方法以及有参无参构造

    public Integer getId() {
        return id;
    }

    public void setId(Integer id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public Short getAge() {
        return age;
    }

    public void setAge(Short age) {
        this.age = age;
    }

    public Short getGender() {
        return gender;
    }

    public void setGender(Short gender) {
        this.gender = gender;
    }

    @Override
    public String toString() {
        return "User{" +
                "id=" + id +
                ", name='" + name + '\'' +
                ", age=" + age +
                ", gender=" + gender +
                '}';
    }

    public User() {
    }

    public User(Integer id, String name, Short age, Short gender) {
        this.id = id;
        this.name = name;
        this.age = age;
        this.gender = gender;
    }
}

配置 Mybatis

image.png

#驱动类名称
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
#数据库连接的url
spring.datasource.url=jdbc:mysql://localhost:3306/mybatis
#连接数据库的用户名
spring.datasource.username=root
#连接数据库的密码
spring.datasource.password=123456

数据库的名字为 mybatis,数据库的密码为 123456
要依据具体情况修改

编写 SQL 语句(这里使用注解的方式)

  • 创建接口

image.png
代码如下:

package com.example.mapper;

import com.example.pojo.User;
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Select;

import java.util.List;

@Mapper //在运行时,会自动生成该接口的实现类对象(代理对象),并将该对象交给IOC容器管理
public interface UserMapper {
    //查询全部用户信息
    //全部用户信息使用list集合
    @Select("select * from user")
    public List<User> list();
}

代码测试

image.png
在这个测试类中编写如下代码:

package com.example;

import com.example.mapper.UserMapper;
import com.example.pojo.User;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;

import java.util.List;

/**
 * 这是SpringBoot工程自带的一个测试类
 */

@SpringBootTest//SpringBoot整合单元测试的注解
class DemoMybatisApplicationTests {

    /*
    写一个测试方法来进行测试
    查询所有用户的信息
    来调用UserMapper接口中的list方法
    UserMapper是一个接口,不能直接new接口
     但是,在Usermapper接口上加了Mapper注解,会自动生成代理对象
     */
    //所以直接声明一个UserMapper的对象,再加上注解进行依赖注入
    @Autowired
    private UserMapper userMapper;
    @Test
    public void testListUser(){
        //直接调用方法进行查询
        List<User> userList = userMapper.list();
        //进行遍历输出
        userList.stream().forEach(user ->{
            System.out.println(user);
        });
    }

}

结果如下则成功
image.png

在 IDE 写的 sql 语句如果表名爆红
image.png
image.png
image.png
然后右侧就会加载出相关数据库的表格信息
image.png

JDBC 介绍

  • JDBC 是使用 Java 语言操作关系型数据库的一套 API

JDBC,全称Java DataBase Connectivity(java数据库连接),是一种用于执行SQL语句的Java API,可以为多种关系数据库提供统一访问。它是由一组用java语言编写的类和接口组成,是sun公司制定的一套接口(interface),接口都有调用者和实现者。JDBC为程序开发人员提供了一组用于实现对数据库访问的JDBCAPI,并支持SQL语言,是sun开发的一套数据库访问编程接口,是一种SQL级的API。
JDBC的作用在于降低了程序的耦合度,提高了程序的扩展力。它通过驱动程序管理类(DriverManager)这个JDBC的管理类,作用于用户和驱动程序之间,提供了一种基准,据此可以构建更高级的工具和接口,使数据库开发人员能够编写数据库应用程序。
利用JDBC可以将JAVA代码连接到多种数据库,如oracle、DB2、SQLServer、MYSQL等,从而实现对数据库中的数据操作的目的。同时,JDBC具有很好的跨平台特性,使用JDBC编写的数据库应用程序可以在任何支持java的平台上运行,而不必在不同的平台上编写不同的应用程序。


Java、MySQL、JDBC、MyBatis和MyBatis Plus之间的关系、联系和区别如下:

  1. Java:Java是一种广泛使用的编程语言,它最初是由Sun Microsystems开发,现在由Oracle公司进行维护和发布。Java提供了一种平台无关的编程方式,使得开发人员可以编写一次代码,然后在任何支持Java的平台上运行。
  2. MySQL:MySQL是一种流行的开源关系数据库管理系统(RDBMS),它使用SQL(结构化查询语言)作为其查询语言。MySQL具有高性能、可靠性和易于使用的特点,被广泛用于各种应用程序和网站。
  3. JDBC:Java Database Connectivity(JDBC)是Java提供的一套用于和数据库对接的API。它提供了一种标准的接口,使得Java应用程序可以通过JDBC连接到各种关系数据库。MyBatis框架则是在此基础上进行了进一步的封装和简化。
  4. MyBatis:MyBatis是一个流行的Java持久层框架,它封装了JDBC,使得开发人员可以更加方便地与数据库进行交互。MyBatis通过配置文件来定义SQL语句,这使得SQL语句可以与Java代码分离,更易于维护和修改。
  5. MyBatis Plus:MyBatis Plus是MyBatis的增强工具,它在MyBatis的基础上提供了更多的功能和简化的操作。MyBatis Plus支持MyBatis的所有特性,并提供了基本的CRUD(创建、读取、更新、删除)功能,不需要开发人员自己编写SQL语句。此外,MyBatis Plus还引入了条件构造器(Querydsl),可以方便地构造复杂的查询条件。

总结起来,Java是编程语言,MySQL是数据库管理系统,JDBC是Java和MySQL之间的连接桥梁,而MyBatis和MyBatis Plus是在JDBC基础上进一步封装和简化的持久层框架。

JDBC 的代码使用就不需要详细掌握了

数据库连接池

  • 数据库连接池
    • 数据库连接池是一个容器,负责分配、管理数据库连接
    • 允许应用程序重复使用一个现有的数据库连接,而不是再重新建立一个
    • 释放空闲时间超过最大空闲时间的连接,来避免因为没有释放连接而引起的数据库连接遗漏
  • 优势
    • 资源重用
    • 提升系统响应速度
    • 避免数据库连接遗漏

数据库连接池是计算机技术中的一种特殊池,用于存储和复用数据库连接。我们可以将其类比为现实生活中的游泳池。

在日常生活中,如果我们想要游泳,通常需要去游泳池。游泳池为我们提供了方便的游泳场所,并节省了我们每一次都必须挖掘一个新的泳池的费用和时间。池中的水可以被不同的人共享,高效地利用了水资源。

类似地,当我们需要与数据库进行交互时,我们通常需要创建数据库连接。创建数据库连接需要消耗计算资源和时间,而且如果每个请求都创建新的数据库连接,系统性能会大大降低。这时,数据库连接池就发挥作用了。

数据库连接池就像一个有多个泳道的游泳池。每个泳道都像一个数据库连接,而泳道中的水就像数据库连接的资源。这些资源被多个用户共享,而不是每个用户都创建新的资源。这样,我们就可以更高效地利用系统资源,提高系统性能。

具体来说,当我们需要与数据库交互时,我们从数据库连接池中获取一个可用的数据库连接,就像从泳道中借一个游泳圈一样。用完后,我们把这个连接放回连接池中,就像把游泳圈还回泳道一样。如果连接池中没有可用的连接,那么将会自动创建新的连接。就像如果所有的游泳圈都被借走了,那么游泳池管理员会再放入一些新的游泳圈。

同时,数据库连接池还可以对连接进行管理和监控。比如当一个连接被使用时,连接池可以记录这个连接的创建时间、最近一次使用时间等信息,并在需要时自动关闭那些长时间未被使用的连接,释放系统资源。就像游泳池管理员会根据泳道的占用情况来关闭那些没有人使用的泳道,节省水资源。

因此,数据库连接池通过复用数据库连接、管理和监控连接等作用,提高了系统性能和资源利用率。


在数据库连接池中,如果所有的连接都被占满了,有以下几种解决办法:

  1. 等待:如果所有的连接都在被高频率地使用,但是并没有空闲连接,那么你可以选择等待,直到有连接空出来。
  2. 创建新的连接池:如果你需要更多的连接,你可以创建新的连接池。
  3. 优化连接使用:在连接池中,如果连接被占满了,也可以通过优化连接使用来进行解决。比如可以对连接进行分类,对不同类型的连接进行管理和复用,以更高效地利用系统资源。

因此,当游泳池中的泳道被占满了时,我们可以选择等待、提高泳姿或者寻找其他泳池。而在数据库连接池中,我们可以选择等待、创建新的连接池或者优化连接使用。

image.png
不同的编程语言和数据库系统有不同的默认连接池。以下是一些常见的默认连接池:

  1. Java语言中,使用JDBC连接数据库时,如果没有指定连接池,则默认使用的是“c3p0”或者“HikariCP”连接池。其中,HikariCP在Spring Boot 2.x版本之后被选为默认的数据库连接池。
  2. MySQL的默认连接池是“c3p0”,可以通过在配置文件中指定“default-pool-size”参数来设置默认的最大连接数。
  3. PostgreSQL的默认连接池是“yadcf”,也可以使用第三方的连接池如“pgbouncer”来作为默认的连接池。
  4. Oracle数据库的默认连接池是“Generic”类型的,可以通过在配置文件中指定“MAX_POOL_SIZE”参数来设置默认的最大连接数。

需要注意的是,默认连接池可能因不同的版本和配置而有所不同,如果需要使用自定义的连接池,则需要在配置中进行相应的设置和指定。


切换数据库连接池
image.png

Lombok

image.png
引入 Lombok 依赖才能使用 Lombo 注解

        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
        </dependency>

image.png
这个时候,在原先的实体类中,注释掉 setter、getter、toString、构造方法
使用 Data 注解即可
运行结果依旧正确:
image.png

Mybatis 基础操作

准备工作

  • 准备数据库 emp
  • 创建一个新的 SpringBoot 工程,选择引入对应的起步依赖
  • aapplication.properties 引入数据库连接信息
  • 创建对应的实体类 Emp
  • 准备 Mapper 接口 EmpMapper
  1. 创建数据库表格
-- 部门管理
create table dept(
    id int unsigned primary key auto_increment comment '主键ID',
    name varchar(10) not null unique comment '部门名称',
    create_time datetime not null comment '创建时间',
    update_time datetime not null comment '修改时间'
) comment '部门表';

insert into dept (id, name, create_time, update_time) values(1,'学工部',now(),now()),(2,'教研部',now(),now()),(3,'咨询部',now(),now()), (4,'就业部',now(),now()),(5,'人事部',now(),now());



-- 员工管理
create table emp (
  id int unsigned primary key auto_increment comment 'ID',
  username varchar(20) not null unique comment '用户名',
  password varchar(32) default '123456' comment '密码',
  name varchar(10) not null comment '姓名',
  gender tinyint unsigned not null comment '性别, 说明: 1, 2 女',
  image varchar(300) comment '图像',
  job tinyint unsigned comment '职位, 说明: 1 班主任,2 讲师, 3 学工主管, 4 教研主管, 5 咨询师',
  entrydate date comment '入职时间',
  dept_id int unsigned comment '部门ID',
  create_time datetime not null comment '创建时间',
  update_time datetime not null comment '修改时间'
) comment '员工表';

INSERT INTO emp
	(id, username, password, name, gender, image, job, entrydate,dept_id, create_time, update_time) VALUES
	(1,'jinyong','123456','金庸',1,'1.jpg',4,'2000-01-01',2,now(),now()),
	(2,'zhangwuji','123456','张无忌',1,'2.jpg',2,'2015-01-01',2,now(),now()),
	(3,'yangxiao','123456','杨逍',1,'3.jpg',2,'2008-05-01',2,now(),now()),
	(4,'weiyixiao','123456','韦一笑',1,'4.jpg',2,'2007-01-01',2,now(),now()),
	(5,'changyuchun','123456','常遇春',1,'5.jpg',2,'2012-12-05',2,now(),now()),
	(6,'xiaozhao','123456','小昭',2,'6.jpg',3,'2013-09-05',1,now(),now()),
	(7,'jixiaofu','123456','纪晓芙',2,'7.jpg',1,'2005-08-01',1,now(),now()),
	(8,'zhouzhiruo','123456','周芷若',2,'8.jpg',1,'2014-11-09',1,now(),now()),
	(9,'dingminjun','123456','丁敏君',2,'9.jpg',1,'2011-03-11',1,now(),now()),
	(10,'zhaomin','123456','赵敏',2,'10.jpg',1,'2013-09-05',1,now(),now()),
	(11,'luzhangke','123456','鹿杖客',1,'11.jpg',5,'2007-02-01',3,now(),now()),
	(12,'hebiweng','123456','鹤笔翁',1,'12.jpg',5,'2008-08-18',3,now(),now()),
	(13,'fangdongbai','123456','方东白',1,'13.jpg',5,'2012-11-01',3,now(),now()),
	(14,'zhangsanfeng','123456','张三丰',1,'14.jpg',2,'2002-08-01',2,now(),now()),
	(15,'yulianzhou','123456','俞莲舟',1,'15.jpg',2,'2011-05-01',2,now(),now()),
	(16,'songyuanqiao','123456','宋远桥',1,'16.jpg',2,'2010-01-01',2,now(),now()),
	(17,'chenyouliang','123456','陈友谅',1,'17.jpg',NULL,'2015-03-21',NULL,now(),now());
  1. 创建项目、导入依赖

image.pngimage.pngimage.png

  1. 引入数据库链接信息

image.png

  1. 创建对应的实体类 Emp

image.png
使用驼峰命名法
image.png

  1. 准备 Mappe 接口

image.png

删除

编写 SQ 语句

image.png

在这里,@Delete后面写的是“delete from emp where id = #{id}”;而不是“delete from emp where id = 7 ”
因为,如果是后者,就会静态的只能删除 i 为 7 的数据,前者可以 在方法参数中设置传入的参数的值,在 sq 语中,#{id}来接收传进来的 i 值

如果将这里的 void 变为 int,最后测试的时候返回的是这个 sq 语影响的行数

代码测试

image.png

    @Test
    public void testDeleteById(){
        empMapper.deleteById(17);
    }

添加

编写 SQ 语句image.png

    @Insert("insert into emp(username,name,gender,image,job,entrydate,dept_id,create_time,update_time)"+
    "values(#{username},#{name},#{gender},#{image},#{job},#{entrydate}," +
            "#{deptId},#{createTime},#{updateTime})")
    public void insert(Emp emp);

这里同样将 SQ 语设置为动态的,只不过在方法的形参列表中传递的不是一个个的参数,而是实体类 Emp 的对象 emp,在调用方法的时候,设置并传入 emp 的相应的参数

代码测试

image.png

    @Test
    public void testInsert(){
        //构造员工对象
        Emp emp =new Emp();
        emp.setUsername("zhang");
        emp.setName("张章");
        emp.setImage("1.png");
        emp.setGender((short)1);
        emp.setJob((short)1);
        emp.setEntrydate(LocalDate.of(2000,1,1));
        emp.setCreateTime(LocalDateTime.now());
        emp.setUpdateTime(LocalDateTime.now());
        emp.setDeptId(1);

        //执行新增员工信息操作
        empMapper.insert(emp);
    }

添加时返回主键

  • 描述:在数据添加成功后,需要获取插入数据库数据的主键。如:添加套餐数据时,还需要维护套餐菜品关系表数据。

image.png
如果直接输出获取主键,会发现返回的是 Null 而无法获得主键

  • 实现:

image.png

只需要在@insert注解上面加上 options 注即可,这里第一个属性表示主键是 id 字段,第二个属性表示要获取主键

这时候,再添加一次数据,发现可以返回主键了
image.png

更新

编写 SQ 语句

image.png

    @Update("update emp set username=#{username},name=#{name},gender=#{gender},image=#{image}," +
            "job=#{job},entrydate=#{entrydate},dept_id=#{deptId},update_time=#{updateTime} where id=#{id}")
    public void update(Emp emp);

代码测试

image.png

    @Test
    public void testUpdate(){
        //构造员工对象
        Emp emp =new Emp();
        emp.setId(1);
        emp.setUsername("haenggg");
        emp.setName("张g11111章");
        emp.setImage("121.png");
        emp.setGender((short)1);
        emp.setJob((short)1);
        emp.setEntrydate(LocalDate.of(2000,1,1));
        emp.setUpdateTime(LocalDateTime.now());
        emp.setDeptId(1);

        //执行更新员工信息操作
        empMapper.update(emp);

    }

查询全部

编写 SQ 语句

image.png

代码测试

image.png

根据 id 查询

编写 SQ 语句

image.png

代码测试

image.png

出现的问题以及解决

image.png
但是后面的几项查询结果都是 Null
image.png
解决方案

  • 方案一

image.png

  • 方案二

image.png

  • 方案三★★★

image.png

条件查询

编写 SQL 语句

image.png

    @Select("select * from emp where name like '%${name}%' and gender = #{gender} and " +
            "entrydate between #{begin} and #{end} order by update_time desc ")
    public List<Emp> list(String name, Short gender, LocalDate begin , LocalDate end);

代码测试

image.png
image.png

xml 映射文件

快速入门

image.png

image.png

将 mapper 接口的注解注释掉,只保留方法
image.png
EmpMapper.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.mapper.EmpMapper">
    <select id="list" resultType="com.example.pojo.Emp">
        select * from emp where name like concat('%',#{name},'%') and gender = #{gender} and
                                entrydate between #{begin} and #{end} order by update_time desc
    </select>
</mapper>

运行测试方法也可成功
image.png
下载 MybatisX 插件

动态SQL

if

随着用户的输入或外部条件的变化而变化的SQL语句,我们称为动态SQL。
image.png
如果将 test 中的查询条件只设置 name,其他为 null,则无法查询到结果,因为此时是静态的,接口中设置了几个查询条件 test 中就要查询几个条件


这时候可以在 xml 配置文件中编写如下 SQL代码

<?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.mapper.EmpMapper">
    <select id="list" resultType="com.example.pojo.Emp">
        select *
        from emp
        where
            <if test="name!=null">
                name like concat('%',#{name},'%')
            </if>
            <if test="gender!=null">
                and name like concat('#{gender}')
            </if>
            <if test="begin!=null and end!=null">
                and entrydate between #{begin} and #{end}
            </if>
        order by update_time desc
    </select>
</mapper>

设置动态 sql
即可查询所有姓名中带有”张“的信息
同理,如果这时候查询条件只有两个也可以
image.png
但是,如果这样查询就会报错,因为如果第一个条件为 null,sql 语句就会开头出现 and 而语法错误
image.png
这个时候可以使用标签
image.png

if 案例—动态更新

在之前的更新的时候,有些字段需要更新,有些字段不需要更新,所以写代码的时候只需要写需要进行更新的字段就行了,但是,如果不需要更新的字段不写,就会默认更新为 null
如果要使用动态 SQL,则只需要写想要更新的字段,其他字段不会改变而不会变成 null
image.png
使用 xml 配置文件
在接口文件中编写一个 update 方法
会发现报错为没有 xml 映射文件的 sql 代码,这时候鼠标放在红线上,点击image.png即可在 xml 文件中创建(因为安装了 MybatisX 插件)
image.png
将更新 SQL语句更写为如下:
image.png

对于这里的标签,如果只更改 username,那么后面的都不会成立,那么,会多一个逗号image.png
会语法错误,使用 set 标签可解决这个问题

即可动态更新
此时如果只想将 id 为 1 的 name 改为 qqqqq
image.png

foreach

image.pngimage.png

<mapper namespace="com.example.mapper.EmpMapper">
    <!--批量删除员工 (1,2,3)-->
    <!--
        collection: 遍历的集合
        item: 遍历出来的元素
        separator: 分隔符
        open: 遍历开始前拼接的SQL片段
        close: 遍历结束后拼接的SQL片段
    -->
    <delete id="deleteByIds">
        delete  from emp where id in
        <foreach collection="ids" item="id" separator="," open="(" close=")">
            #{id}
        </foreach>
    </delete>

image.png

sql 和 include

image.png
image.png

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

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

相关文章

adb调试Linux嵌入式设备记录

1. ADB的全称为Android Debug Bridge&#xff0c;调试设备或调试开发的Android APP。 2.adb的windows下载安装路径&#xff1a;SDK 平台工具版本说明 | Android 开发者 | Android Developers 3.linux中安装adb,参考该链接&#xff1a; https://www.cnblogs.com/androidsu…

Springboot+vue的财务管理系统(有报告),Javaee项目,springboot vue前后端分离项目。

演示视频&#xff1a; Springbootvue的财务管理系统&#xff08;有报告&#xff09;&#xff0c;Javaee项目&#xff0c;springboot vue前后端分离项目。 项目介绍&#xff1a; 本文设计了一个基于Springbootvue的前后端分离的财务管理系统&#xff0c;采用M&#xff08;model…

基于Seata的分布式事务方案

在Seata中&#xff0c;有4种分布式事务实现方案 XA、AT、TCC、Saga 其中XA利用了数据库的分布式事务特性&#xff0c;AT相当于框架去控制事务回滚。TCC手写三个方法&#xff0c;saga手写两个方法。 AT的性能和编写比较折中&#xff0c;是最常用的一种。TCC一些视频教程中介绍…

windows系统安装openssl并且转换证书格式

概述 碎碎念&#xff0c;如果你有MAC电脑&#xff0c;就别折腾了&#xff0c;直接用MAC电脑吧,不用安装直接用openssl 本文主要讲到了openssl的基本使用方法&#xff0c;开发环境为windows&#xff0c;开发工具为VS2019.本文主要是说明openssl如何使用&#xff0c;不介绍任何理…

判断某点是否在三角形内(Python)

已知三角形的三个顶点坐标&#xff0c;判断某个点是否在三角形中&#xff08;在三角形的边上&#xff0c;我们也视作在三角形中&#xff09;&#xff0c;我们提供不同的方法。 方法1&#xff1a;内角和等于360 方法2&#xff1a;等面积法 即对于△ABC内的某一点P&#xff0c;…

LInux文件权限相关知识介绍

LInux文件权限相关知识分享&#x1f60e; 前言&#x1f64c;Linux相关权限的概念&#xff1a;文件类型基本权限文件访问权限的相关设置方法chmod① 用户表示符/-权限字符②三位8进制数字 总结撒花&#x1f49e; &#x1f60e;博客昵称&#xff1a;博客小梦 &#x1f60a;最喜欢…

java+springboot+vue高校毕业生就业统计管理系统022xr

系统的设计与实现采用Spring、SpringMVC和MyBatis作为主体框架,系统设计遵循界面层、业务逻辑层和数据访问层的Web开发三层架构。采用B/S结构,使得系统更加容易维护。系统的设计与实现主要实现角色有管理员和用户,管理员在后台管理用户表模块、token表模块、生源信息模块、招聘…

代码随想录Day19 LeetCode T669修剪二叉搜索树 LeetCode T108将有序数组转化为二叉搜索树 T538 把二叉搜索树转化为累加树

LeetCode T669 修剪二叉搜索树 题目链接:669. 修剪二叉搜索树 - 力扣&#xff08;LeetCode&#xff09; 题目思路 这题我们有几个思路需要避坑,首先我们不能这样想,比如遇见比low值还小的节点值,不能直接返回null,而是考虑该节点的右子树有没有符合题目需求的节点值存在,同理删…

Java学习之TreeSet

Java TreeSet 底层是红黑树实现 将元素插入TreeSet add() - 将指定的元素插入集合 addAll() - 将指定集合的所有元素插入集合 import java.util.TreeSet;class Main {public static void main(String[] args) {TreeSet<Integer> evenNumbers new TreeSet<>();/…

二十三、【五种图层】

文章目录 像素图层智能图层文字图层形状图层调整图层 像素图层 像素图层由空白像素图层组成&#xff0c;上边没有任何颜色&#xff0c;如下图&#xff0c;我们可以使用画笔工具在空白相处图层上进行修改&#xff1a; 智能图层 智能图层可以记录该图层当前的数据在被编辑后可…

ShareX使用说明——优秀的录屏软件

ShareX初识 ShareX 是一个自由及开放源代码的截图录像软件&#xff0c;目前仅支持Windows系统。 项目源代码在GitHub平台上发布&#xff0c; 软件可以在Microsoft商店和Steam上下载。 ShareX is a free and open source program that lets you capture or record any area of y…

VPN的不同种类及现网应用场景

学习目标&#xff1a; 1. 企业为什么要部署VPN&#xff1f; 2. 常见的VPN有哪些种类&#xff1f; 3. VPN如何保障数据传输安全&#xff1f; -- VPN - 虚拟私有网络 - 企业最常用的功能之一 - 增值型业务 -- 需求&#xff1a;大一些公司 分公司 - 管理问题 --…

通过jsoup抓取谷歌商店评分

文章目录 背景实现是否下架预警评分 总的工具类,测试 背景 在谷歌上面发布包,有时候要看看评分,有时候会因为总总原因被下架,希望后台能够对评分进行预警,和下架预警 实现 测试地址: https://play.google.com/store/apps/details?idcom.tencent.mm 通过jsoup解析页面,然后获…

项目管理之六大目标及成功方程式

项目管理的六大目标分别是范围、质量、时间、成本、收益和风险。在项目开始之前&#xff0c;需要明确了解项目的范围&#xff0c;并在项目执行过程中对范围进行严格控制&#xff0c;确保项目不偏离既定的范围。同时&#xff0c;需要明确项目的质量标准和预期成果&#xff0c;然…

采用 guidance 提高大模型输出的可靠性和稳定性

本文首发于博客 LLM 应用开发实践 在复杂的 LLM 应用开发中&#xff0c;特别涉及流程编排和多次 LLM 调用时&#xff0c;每次的 Prompt 设计都取决于前一个步骤的大模型输出。如何避免大语言模型的"胡说八道"&#xff0c;以提高大语言模型输出的可靠性和稳定性&#…

1.13.C++项目:仿muduo库实现并发服务器之TcpServer模块的设计

文章目录 一、LoopThreadPool模块二、实现思想&#xff08;一&#xff09;管理&#xff08;二&#xff09;流程&#xff08;三&#xff09;功能设计 三、代码 一、LoopThreadPool模块 TcpServer模块&#xff1a; 对所有模块的整合&#xff0c;通过 tcpserver 模块实例化的对象&…

C++指针解读(3)-- 指针变量作为函数参数

函数执行是通过系统栈来实现的&#xff0c;系统栈分为若干个栈帧。栈帧就是函数运行的环境&#xff0c;每个函数在被调用时都会在系统栈区形成一个叫栈帧的结构。一次函数调用相关的数据保存在栈帧中&#xff0c;比如函数参数、函数的局部变量、函数执行完后的返回地址等数据。…

【LeetCode刷题(数据结构)】:另一颗树的子树

给你两棵二叉树 root 和 subRoot 检验 root 中是否包含和 subRoot 具有相同结构和节点值的子树。如果存在&#xff0c;返回 true &#xff1b;否则&#xff0c;返回 false 二叉树 tree 的一棵子树包括 tree 的某个节点和这个节点的所有后代节点。tree 也可以看做它自身的一棵子…

PCL点云处理之基于强度特征的SIFT关键点提取法 (二百一十五)

PCL点云处理之基于强度特征的SIFT关键点提取法 (二百一十五) 一、算法介绍二、具体实现1.代码2.效果一、算法介绍 继续SIFT关键点的提取介绍,之前已经基于高程和颜色分别提取了关键点,这里是基于强度信息,若遇到文件无法读取强度问题,请参考上一篇博文,下面是具体的实现…

SQL语句-中级

一、Mysql软件使用 1.启动/停止Mysql服务器 任务管理器 cmd命令&#xff1a;以管理员的身份打开cmd命令行 net start mysql80//开启net stop mysql80//停止 2.连接与断开Mysql服务器 注意要在bin目录下执行:-u用户名root&#xff0c;-p密码 mysql -u root -p 可能出现的…