Mybatis - 基础

news2025/1/23 3:10:43

文章目录

  • 一、 Mybatis基本介绍
  • 二、 Mybatis 快速入门程序
    • 2.1 引入Mybatis依赖
    • 2.2 准备工作
    • 2.3 配置SQL信息
      • 2.3.1 IDEA连接数据库
      • 2.3.2 打开日志信息
    • 2.4 JDBC 了解
    • 2.5 数据库连接池
      • 2.5.1 Druid数据库连接池
  • 三、 Mybatis 基础
    • 3.1 环境准备
      • 3.1.1 数据库表
      • 3.1.2 实体类
    • 3.2 基础操作
      • 3.2.1 删除
      • 3.2.2 预编译SQL
        • 3.2.2.1 性能更高
        • 3.2.2.2 更安全
        • 3.2.2.3参数占位符
      • 3.2.3 新增
        • 3.2.4.1 主键返回
      • 3.2.4 更新
      • 3.2.5 查询
      • 3.2.6 条件查询
      • 3.2.7 数据封装
  • 四、 XML映射文件
    • 4.1 案例
    • 4.2 MybatisX 插件
  • 五、Mybatis 动态SQL
    • 5.1 \<if\>
    • 5.2 \<if\> 案例
    • 5.3 \<foreach\>
    • 5.4 \<sql\> \<include\>
    • 5.4 \<sql\> \<include\>

一、 Mybatis基本介绍

​ Mybatis 持久层框架,用于简化JDBC开发

官网: https://mybatis.org/mybatis-3/zh/index.html

二、 Mybatis 快速入门程序

2.1 引入Mybatis依赖

<!--mybatis 起步依赖-->
<dependency>
    <groupId>org.mybatis.spring.boot</groupId>
    <artifactId>mybatis-spring-boot-starter</artifactId>
    <version>2.1.1</version>
</dependency>
    
<!--MySQL驱动包 -->
<dependency>
    <groupId>mysql</groupId>
    <artifactId>mysql-connector-java</artifactId>
    <version>8.0.19</version>
</dependency>

最新发布的MySQL驱动包,但是我们一般还是使用上面的驱动包

<dependency>
    <groupId>com.mysql</groupId>
    <artifactId>mysql-connector-j</artifactId>
    <scope>runtime</scope>
</dependency>

2.2 准备工作

数据库相关信息: 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');

相关实体类

public class User {
    private Integer id; //id(主键)
    private String name; //姓名
    private Short age; //年龄
    private Short gender; //性别
    private String phone; //手机号
//省略GET, SET方法
}

配置信息:

spring:
  datasource:
    driver-class-name: com.mysql.cj.jdbc.Driver
    url: jdbc:mysql://localhost:3306/mybatis?serverTimezone=Asia/Shanghai&useUnicode=true&characterEncoding=utf-8&zeroDateTimeBehavior=convertToNull&useSSL=false&allowPublicKeyRetrieval=true
    username: root
    password: root

Mapper

@Mapper // 在运行时,会自动生成该接口的实现类对象(代理对象),并且将该对象交给IOC容器管理
public interface UserMapper {

//  查询全部用户信息
    @Select("select * from user") // 要执行的sql语句
    public List<User> list();

}

测试程序

@SpringBootTest
class SpringbootWebApplicationTests {
    @Autowired
    private UserMapper userMapper;

    @Test
    void contextLoads() {
        List<User> list = userMapper.list();
        System.out.println(list);
    }

}

2.3 配置SQL信息

如果报错,原因

  • IDEA和数据库没有建立连接,不识别信息

解决方式

  • 在IDEA中配置Mysql数据库连接

image-20230512161010558

2.3.1 IDEA连接数据库

下图中URL信息填写 2.2配置中的URL即可

image-20230512161938609

2.3.2 打开日志信息

mybatis:
  configuration.log-impl: org.apache.ibatis.logging.stdout.StdOutImpl

2.4 JDBC 了解

之前做的JDBC笔记

https://blog.csdn.net/weixin_51351637/article/details/124709121

JDBC:Java DataBase Connectivity,就是使用Java语言操作关系型数据库的一套API

各个数据库厂商去实现这套接口,提供数据库驱动jar包

image-20230512162608626

2.5 数据库连接池

  • 数据库连接池是一个容器,负责分配、管理数据库连接(Connection)
  • 允许应用程序重复使用一个现有的数据库连接,而不是再重新创建一个
  • 释放空闲时间超过最大空闲时间的连接,来避免因为没有释放连接而引起的数据库链接遗漏

优点:

​ 资源重用、提升系统响应速度、避免数据库连接遗漏

没有数据库连接池时:

首先创建一个新的连接对象,再执行这条SQL语句,执行完毕后把这个连接对象关闭了来释放资源

有数据库连接池:

​ 程序在启动时就会在容器当中初始化一定数量的连接对象,客户端在执行SQL语句的时候就会从连接池当中获取一个连接,获取连接之后再执行SQL语句,SQL语句执行完毕之后会把连接再归还给连接池。这样就可以做到连接的复用。

​ 除此之外,当客户占用连接时间过长但没有执行SQL语句并且超过连接池规定的最大空闲时间时,数据库连接池会收回连接

2.5.1 Druid数据库连接池

Maven坐标

<dependency>
    <groupId>com.alibaba</groupId>
    <artifactId>druid-spring-boot-starter</artifactId>
    <version>1.2.8</version>
</dependency>
spring:
  #指定应用的名称,这一项不是必须的,如果不配置的话默认的时候工程名
  application:
    name: SpringBootWeb
  #数据源
  datasource:
    #德鲁伊连接池
    druid:
      driver-class-name: com.mysql.cj.jdbc.Driver
      url: jdbc:mysql://localhost:3306/reggie?serverTimezone=Asia/Shanghai&useUnicode=true&characterEncoding=utf-8&zeroDateTimeBehavior=convertToNull&useSSL=false&allowPublicKeyRetrieval=true
      username: root

三、 Mybatis 基础

3.1 环境准备

  • 准备数据库表emp、dept
  • 创建对应实体类

3.1.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());

3.1.2 实体类

@Data
@NoArgsConstructor
@AllArgsConstructor
public class Emp {
    private Integer id;
    private String username;
    private String password;
    private String name;
    private Short gender;
    private String image;
    private Short job;
    private LocalDate entrydate; //LocalDate类型对应数据表中的date类型
    private Integer deptId;
    private LocalDateTime createTime;//LocalDateTime类型对应数据表中的datetime类型
    private LocalDateTime updateTime;
}

3.2 基础操作

3.2.1 删除

注意: Mapper接口方法形参只有一个普通类型的参数,#{x}里面的属性名可以随便写,如#{id},#{value}

//  根据ID删除数据
//  #{id} 占位符
    @Delete("delete from emp where id = #{id}")
    public void delete(Integer id);

3.2.2 预编译SQL

还是使用下面的代码进行演示,我们已经开始mybatis日志信息,我们关注一下

//  根据ID删除数据
//  #{id} 占位符
    @Delete("delete from emp where id = #{id}")
    public void delete(Integer id);

**日志信息:**注意看黑体部分,Parameters替换掉Preparing中占位符

对于黑体部分有一个专业的名字:预编码SQL

Creating a new SqlSession
SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@1640c151] was not registered for synchronization because synchronization is not active
2023-05-13 11:24:21.721 INFO 12456 — [ main] com.zaxxer.hikari.HikariDataSource : HikariPool-1 - Starting…
2023-05-13 11:24:21.984 INFO 12456 — [ main] com.zaxxer.hikari.HikariDataSource : HikariPool-1 - Start completed.
JDBC Connection [HikariProxyConnection@1905114489 wrapping com.mysql.cj.jdbc.ConnectionImpl@20134094] will not be managed by Spring
==> **Preparing: delete from emp where id = ? **
> Parameters: 20(Integer)
<
Updates: 0
Closing non transactional SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@1640c151]

为什么采用预编译SQL?

  • 性能更高
  • 更安全(防止SQL注入)

3.2.2.1 性能更高

在java中编写了一条SQL语句,SQL语句要想执行就需要连接上数据库,然后才能将SQL语句发送给mysql数据库服务器

发送给服务器之后,服务器并不是立刻执行,而是要经历 “SQL语法解析检查” -> “优化SQL” -> “编译SQL” -> “执行SQL”

MySQL服务器为了效率,会将优化编译后的结果缓存起来(“SQL语法解析检查” -> “优化SQL” -> “编译SQL”的最终结果)。下一次执行SQL的时候会先检查缓存当中是否有编译好的SQL语句,如果有就不用再执行这一系列操作了,直接执行SQL语句;如果没有的话,将四步进行完成,然后存入到缓存空间中

在“执行SQL”操作的时候,会将Parameters参数替换Preparing中的占位符

3.2.2.2 更安全

SQL注入:通过操作输入的数据来修改事先定义好的SQL语句,以达到执行代码对服务器进行攻击的方法。

假设我们不防止SQL注入(没有预编译),就会出现用户名和密码都错误但是还能登陆成功的情况

​ 用户名:zhangzhang

​ 密码:’ or ‘1’='1

 select * count(*) from emp where username ='zhangzhang' and password ='' or '1'='1'

很明显password已经变成了其他样子: password =‘’ or ‘1’=‘1’ ,password只需要满足后面两个条件中的一个条件即可,并且 ‘1’=‘1’ 永远是true,永远成立

假设我们防止SQL注入(预编译)

预编译语句

 select * count(*) from emp where username = ? and password = ?

此时将用户名与密码输入后,会将 ’ or ‘1’='1 看做一个整体填入到password后面的占位符,所以不存在SQL注入问题

​ 用户名:zhangzhang

​ 密码:’ or ‘1’='1

我们使用Mybatis时怎么选择使用预编译SQL?

在SQL语句中填写占位符,如#{id}

3.2.2.3参数占位符

  • #{…}

​ 执行SQL时,会将#{…}替换为 ? ,生成预编译SQL,会自动设置参数值

使用时机: 参数传递

  • ${…}

​ 拼接SQL,直接将参数拼接在SQL语句中,存在SQL注入问题。

使用时机:如果对表明、列表进行动态设置时使用。

image-20230513172952982

3.2.3 新增

很明显,下面是写死的,我们不需要这种

@Insert("insert into emp(username,name,gender,image,job,entrydate,dept_id,create_time,update_time)"+
"values('Tom','汤姆',1,'1.jpg',1,'2005-01-01',1,now(),now())")
public void insert();

我们选择将字段封装成一个对象,如下所示:

@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);

进行测试

Emp emp = new Emp();
emp.setUsername ("Tom") ;
emp.setName("汤姆") ;
emp. setImage("1.jpg") ;
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);

3.2.4.1 主键返回

主键返回:在数据添加成功后,需要获取插入数据库数据的主键。

如: 添加套餐数据时,还需要维护套餐菜品关系表数据。

步骤:

​ 先保存套餐信息,并获取套餐ID

​ 再保存套餐菜品关联信息(需要记录套餐ID、菜品ID)

所以我们应该学会怎么在保存信息后获取套餐ID

//  keyProperty  主键字段, useGeneratedKeys 代表我们需要拿到生成的主键值
    @Options(keyProperty = "id",useGeneratedKeys = true)
    @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);

3.2.4 更新

SQL语句

@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);

测试

Emp emp = new Emp();
emp.setId(22);
emp.setUsername ("Tom2") ;
emp.setName("汤姆8") ;
emp. setImage("1.jpg") ;
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);

3.2.5 查询

    @Select("select * from emp id=#{id}")
    public Emp getById(Integer id);

测试一下

Emp emp = empMapper.getById(15);
System.out.println(emp);
//Emp(id=15, username=yulianzhou, password=123456, name=俞莲舟, gender=1, image=15.jpg, job=2, entrydate=2011-05-01, deptId=null, createTime=null, updateTime=null)

然后发现deptId=null, createTime=null, updateTime=null这三个字段为null,原因是数据封装出现的问题

3.2.6 条件查询

@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);

注意我们在模糊查询的时候并没有使用#{name},而是使用的${name}

原因:

​ $是字符串拼接的符号,它不会生成和编译SQL。会将传递过来的name和%、{}进行拼接

**如果是用#{name},外面还有单引号,井号与大括号是不能出现在引号之内的,因为#{…}生成的预编译SQL,最后是要被 “?” 代替的,但是占位符“?”是不能出现在引号之内的。 **

但是此时生成的就不是预编译的SQL,存在SQL注入问题。

但是这个问题可以使用SQL中的concat函数 - 拼接字符串 来解决。

@Select("select * from emp where name like concat('%',#{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);

3.2.7 数据封装

数据封装:

  • 实体类属性名和数据库表查询返回的字段名一致,mybatis会自动封装
  • 如果实体类属性名和数据库表查询返回的字段名不一致,不能自动封装

解决方案

  • 方案一 字段起别名
@Select("select id, username, password, name, gender, image, job, entrydate, " +
        "dept_id deptId, create_time createTime, update_time updateTime from emp " +
        "where id=#{id}")
public Emp getById(Integer id);

测试

        Emp emp = empMapper.getById(15);
        System.out.println(emp);
//      Emp(id=15, username=yulianzhou, password=123456, name=俞莲舟, gender=1, image=15.jpg, job=2, entrydate=2011-05-01, deptId=2, createTime=2023-05-13T11:16:16, updateTime=2023-05-13T11:16:16)
 
  • 方案二 通过@Results @Result注解手动映射封装

一个@Result注解映射一个字段和属性

@Results({
        @Result(column = "dept_id",property = "deptId"),
        @Result(column = "create_time",property = "createTime"),
        @Result(column = "update_time",property = "updateTime")
})
@Select("select * from emp where id=#{id}")
public Emp getById(Integer id);
  • 方案三 开始mybatis驼峰命名自动映射开关
@Select("select * from emp where id=#{id}")
public Emp getById(Integer id);
spring:
  datasource:
    driver-class-name: com.mysql.cj.jdbc.Driver
    url: jdbc:mysql://localhost:3306/mybatis?serverTimezone=Asia/Shanghai&useUnicode=true&characterEncoding=utf-8&zeroDateTimeBehavior=convertToNull&useSSL=false&allowPublicKeyRetrieval=true
    username: root
    password: root
mybatis:
  configuration:
    map-underscore-to-camel-case: true
    log-impl: org.apache.ibatis.logging.stdout.StdOutImpl

四、 XML映射文件

中文网:https://mybatis.net.cn/getting-started.html

规范

  • XML映射文件的名称与Mapper接口名称一致,并且将XML映射文件和Mapper接口放置在相同包下(同包同名)

​ 在resource下创建目录的时候不要使用“.”,要使用“/”,比如“com/zhangjingqi/mapper”

  • XML映射文件的namespace属性为Mapper接口全限定名一致

  • XML映射文件中SQL语句的id与Mapper接口中的方法名一致,并保持返回类型一致

image-20230513173645547

使用注解来映射简单语句会使代码显得更加简洁,但对于稍微复杂一点的语句,Java注解不仅力不从心,还会让你本就复杂的SQL语句更加混乱不堪。因此,如果你需要做一些复杂的操作,最好是用XML来映射语句。

4.1 案例

方法名称

public List<Emp> list(String name , Short gender , LocalDate begin, LocalDate end);

配置文件

<?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.zhangjingqi.mapper.EmpMapper">
<!--  resultType 表示单条记录所封装的类型-->
    <select id="list" resultType="com.zhangjingqi.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>

流程

当调用list(…)方法的时候,mybatis框架就会自动查找namespace属性值与这个接口全类名相同的这份xml映射文件。

并且在XML映射文件中找到id属性值与方法名称相同的SQL语句,最终运行SQL语句

4.2 MybatisX 插件

  • MybatisX 是一款基于IDEA快速开发Mybatis的插件,为效率而生。

  • 安装

image-20230513180354759

五、Mybatis 动态SQL

随着用户的输入或外部条件的变化而变化的SQL语句,我们称为动态SQL

5.1 <if>

用于判断条件是否成立。使用test属性进行条件判断,如果条件为true,则拼接SQL

test属性指定条件,满足条件便拼接字符串

where作用

  • 根据字标签动态的判断里面的条件,如果里面条件都不成立,就不会生成where这个关键字

  • where 元素只会在子元素有内容的情况下才插入where子句。会自动取出SQL前面的 and 或者是 or

<if>的作用

  • 比如第一个if与第二个if,加入上面name条件没有成立,那下面这段SQL就会产生错误,多了一个"and"

  • 用于判断条件是否成立。使用test属性进行条件判断,如果条件为true,则拼接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.zhangjingqi.mapper.EmpMapper">
    <!--  resultType 表示单条记录所封装的类型-->
    <select id="list" resultType="com.zhangjingqi.pojo.Emp">
        select *
        from emp

        <where>
            <if test=" name != null">
                name like concat('%',#{name},'%')
            </if>

            <if test=" gender != null">
                and gender = #{gender}
            </if>

            <if test="begin !=null and end !=null">
                and entrydate between #{begin} and #{end}
            </if>
        </where>
        order by update_time desc
    </select>

</mapper>

5.2 <if> 案例

动态更新员工: 更新ID为18的员工

下面是之前的方式,

@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);

有许多的不方便之处,比如我只想更新username、name、updateTime字段,我们调用方法之后,发现除了上面三个字段,其他的都是null(某些字段没有赋值,就会成null),显然不是我们想要的更新结果。

Emp emp = new Emp();
emp.setId(18);
emp.setUsername ("Tom111") ;
emp.setName("汤姆111") ;
emp.setUpdateTime (LocalDateTime.now());
empMapper.update(emp);

下面我们要实现如果有值时就更新,没有值的时候就不更新

**<set>**标签的作用:去掉字段之后多余的","

    <update id="update">
        update emp
        <set>
        <if test="username!=null">
            username = #{username},
        </if>
        <if test="name!=null">
            name = #{name},
        </if>
        <if test="gender!=null">
            gender = #{gender},
        </if>
        <if test="image!=null">
            image = #{image},
        </if>
        <if test="job !=null">
            job= #{job},
        </if>
        <if test="entrydate!=null">
            entrydate= #{entrydate},
        </if>
        <if test="deptId!=null">
            dept_id= #{deptId},
        </if>
        <if test="updateTime!=null">
            update_time= #{updateTime}
        </if>
        </set>
        where id = #{id}
    </update>

5.3 <foreach>

在批量删除的时候会使用

public void deleteByIds(List<Integer> ids);

属性含义

  • collection : 指定要遍历的集合或数组,可以是 List、Set、Array、Map 等类型。遍历操作会把元素依次添加到 SQL 语句中。

  • item:指定遍历时,每次遍历出来的元素的名称。

  • separator:分隔符, 每一次遍历出来的元素在拼接的时候用什么分割

  • open: 指定在遍历列表时,拼接到列表的第一个元素前的 SQL 语句。

  • close: 指定在遍历列表时,拼接到列表的最后一个元素后的 SQL 语句。

配置文件

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

测试类

List<Integer> ids = Arrays.asList(17,18,22);
empMapper.deleteByIds(ids);

控制台SQL日志

image-20230513205124602

5.4 <sql> <include>

<sql> : 定义可重用的SQL片段

<include>: 通过refid,指定包含sql片段

抽取与引用的作用:提高代码的复用性

<sql id="commonSelect">
    select id, username, password,name,gender,image,job,entrydate,dept_id,create_time,update_time
    from emp
</sql>
<select id="list" resultType="com.zhangjingqi.pojo.Emp">
    <include refid="commonSelect"/>

    <where>
        <if test=" name != null">
            name like concat('%',#{name},'%')
        </if>

        <if test=" gender != null">
            and gender = #{gender}
        </if>

        <if test="begin !=null and end !=null">
            and entrydate between #{begin} and #{end}
        </if>
    </where>
    order by update_time desc
</select>
      where id in
      <foreach collection="list" item="id" separator="," open="(" close=")">
          #{id}
      </foreach>
  </delete>



**测试类**

```java
List<Integer> ids = Arrays.asList(17,18,22);
empMapper.deleteByIds(ids);

控制台SQL日志

[外链图片转存中…(img-KcTnam5q-1683982966648)]

5.4 <sql> <include>

<sql> : 定义可重用的SQL片段

<include>: 通过refid,指定包含sql片段

抽取与引用的作用:提高代码的复用性

<sql id="commonSelect">
    select id, username, password,name,gender,image,job,entrydate,dept_id,create_time,update_time
    from emp
</sql>
<select id="list" resultType="com.zhangjingqi.pojo.Emp">
    <include refid="commonSelect"/>

    <where>
        <if test=" name != null">
            name like concat('%',#{name},'%')
        </if>

        <if test=" gender != null">
            and gender = #{gender}
        </if>

        <if test="begin !=null and end !=null">
            and entrydate between #{begin} and #{end}
        </if>
    </where>
    order by update_time desc
</select>

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

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

相关文章

EasyRecovery16中文最新版电脑数据恢复软件下载使用教程

EasyRecovery如果需要使用它来恢复数据&#xff0c;请注意&#xff0c;尤其是当需要恢复的数据文件非常重要时&#xff0c;建议使用软件EasyRecovery以保障数据安全。共有三个版本&#xff0c;分别是个人版、专业版、企业版&#xff0c;这三种都可以免费下载并使用&#xff0c;…

[MySQL]关于MySQL索引的一点点东西

最是人间留不住,朱颜辞镜花辞树. 目录 一.为什么需要索引 1.什么是索引 2.索引的创建原则 二.理解索引 1. MySQL与磁盘交互基本单位 2.索引的结构 a.关于hash索引,B树索引,B树索引的特点 B树 B树 HASH b.为什么使用InnoDB 存储引…

15-721 chapter 13 查询执行

优化的目标 CPU层面 cpu是多级流水线操作&#xff0c;所以我们的目标是让每个处理器的每个部分都处于busy。多条流水线&#xff0c;我们没有依赖的指令可以放到不同的流水线里面。但是流水线如果遇到branch判断错误的话&#xff0c;就要flush掉 可以用值传递来代替跳转 查询执…

Linux开发板安装Python环境

1. 环境介绍 硬件&#xff1a;STM32MP157&#xff0c;使用的是野火出的开发板。 软件&#xff1a;Debian ARM 架构制作的 Linux 发行版&#xff0c;版本信息如下&#xff1a; Linux发行版本&#xff1a;Debian GNU/Linux 10 内核版本&#xff1a;4.19.94 2. Python 简介…

基于常用设计模式的业务框架

前言 做开发也有好几年时间了&#xff0c;最近总结和梳理自己在工作中遇到的一些问题&#xff0c;工作中最容易写出BUG的需求就是改造需求了。一个成熟的业务系统是需要经过无数次迭代而成的&#xff0c;也意味着经过很多开发人员之手&#xff0c;最后到你这里&#xff0c;大部…

每日学术速递5.11

CV - 计算机视觉 | ML - 机器学习 | RL - 强化学习 | NLP 自然语言处理 Subjects: cs.CV 1.Diffusion Explainer: Visual Explanation for Text-to-image Stable Diffusion 标题&#xff1a;扩散解释器&#xff1a;文本到图像稳定扩散的视觉解释 作者&#xff1a;Seongmin…

【数据结构】【算法】二叉树、二叉排序树、树的相关操作

树结构是以分支关系定义的一种层次结构&#xff0c;应用树结构组织起来的数据&#xff0c;逻辑上都具有明显的层次关系。 操作系统中的文件管理系统、网络系统中的域名管理、数据库系统中的索引管理等都使用了树结构来组织和管理数据。 树的基本概念 树Tree是由n个节点组成的有…

数据结构-查找-散列结构(散列表)

目录 *一、散列表 二、散列函数 *除留余数法 *直接定址法 数字分析法 平方取中法 三、冲突处理方法--开发定地法 *3.1线性探测法 *查找效率&#xff1a; *3.2平方探测法 3.3伪随机序列法 3.4再散列法 *一、散列表 又称哈希表&#xff0c;数据元素的关键字与其存储…

bgp团体属性配置案例一

RouterA的配置 sysname RouterA interface GigabitEthernet1/0/0 ip address 192.168.0.1 255.255.255.0 interface LoopBack0 ip address 1.1.1.1 255.255.255.255 bgp 10 router-id 1.1.1.1 //Router ID&#xff0c;建议配置为LoopBack0的IP地址 peer 192.168.0.2 as-number …

【Linux】信号的处理

信号篇终章 文章目录 前言一、信号的处理 1.可重入函数 2.volatile关键字 3.SIGCHLD信号总结 前言 在前两篇linux文章中我们详细的讲解了信号的产生和信号的保存&#xff0c;今天来到最后一个重点信号的处理&#xff0c;对于信号的处理我们会重新引入进程…

如何实现一个高效的H264信源编码器?了解核心算法和实现流程

H264 H264是一种常用的视频编码标准&#xff0c;它以网络传输和存储为设计目的&#xff0c;能够将视频信号进行高效压缩&#xff0c;并保持较高的视频质量。 H264视频编码标准采用的是基于帧的编码方式。每一帧视频都被分为不同的块&#xff0c;每个块中都包含了可压缩的信息…

11.PC端网页特效

PC端网页特效 1. 元素偏移量 offset 系列 1.1 offset 概述 offset 翻译过来就是偏移量&#xff0c; 使用 offset 系列相关属性可以动态的得到该元素的位置&#xff08;偏移&#xff09;、大小等 获得元素距离带有定位父元素的位置获得元素自身的大小&#xff08;宽度高度&a…

03:MYSQL----DQL,聚合函数

目录 1:介绍 2:语法 3:聚合函数 4:DOL 语句练习 5:SQL执行顺序 1:介绍 数据查询语言&#xff0c;用来查询数据库中表的记录 2:语法 select 字段列表 from 表名列表 where 条件列表 group by 分组字段列表 having 分组后字段列表 order by 排序字段列表 limit 分页参…

Vben Admin 自学记录 —— 使用 mock 模拟数据以及模拟api联调接口(持续更新中...)

Vben Admin —— 使用 mock 模拟数据以及模拟api联调接口 数据 mock&联调相关概念及使用 练习 —— 在之前table基础上&#xff0c;使用mock模拟数据&#xff0c;替换原来的死数据&#xff0c;添加新增、查看、修改和删除api并添加逻辑&#xff0c;实现一个简单的、完整的…

《编程思维与实践》1067.小型组合数

《编程思维与实践》1067.小型组合数 题目 思路 法一: 注意到题目数据最大为 C 40 20 137846528820 C_{40}^{20}137846528820 C4020​137846528820在long long的范围内,所以其实可以不用大整数的处理方法去计算: 由于 C m n m ! n ! ( m − n ) ! m ( m − 1 ) . . . ( m −…

mysql数据库的库操作 --2

目录 库操作 2.1&#xff1a;数据库的查看与创建与使用 2.2&#xff1a;字符集和效验规则 2.3&#xff1a;修改和删除数据库 2.4&#xff1a;数据库的备份和恢复 2.5&#xff1a;查看连接情况 库操作 2.1&#xff1a;数据库的查看与创建与使用 2.1.1&#xff1a;数据库…

AcWing算法提高课-1.3.9庆功会

宣传一下算法提高课整理 <— CSDN个人主页&#xff1a;更好的阅读体验 <— 本题链接&#xff08;AcWing&#xff09; 点这里 题目描述 为了庆贺班级在校运动会上取得全校第一名成绩&#xff0c;班主任决定开一场庆功会&#xff0c;为此拨款购买奖品犒劳运动员。 期望…

[golang gin框架] 32.Gin 商城项目- 支付宝支付操作相关功能讲解

一.支付宝支付之前的准备工作 创建应用、配置签名、提交审核 支付宝支付之前的准备工作 支付宝开放平台支持使用 普通公钥、公钥证书 两种签名方式 公钥证书模式下完成支付需要获取的内容&#xff1a; appId 应用私钥 应用公钥证书 支付宝根证书 支付宝公钥证书 普通公钥模式下…

热乎的面经——不屈不挠

⭐️前言⭐️ &#x1f349;欢迎点赞 &#x1f44d; 收藏 ⭐留言评论 &#x1f4dd;私信必回哟&#x1f601; &#x1f349;博主将持续更新学习记录收获&#xff0c;友友们有任何问题可以在评论区留言 &#x1f349;博客中涉及源码及博主日常练习代码均已上传GitHub &#x1f4…

【Linux常见指令以及权限理解】基本指令(3)

写在前面 上一篇文章&#xff0c;我们学习了Linux的一些常用指令&#xff0c; 学习了如何理解Linux系统&#xff0c;介绍了对Linux系统的理解&#xff1a;Linux下一切皆文件 介绍了重定向还有管道相关的知识。这里是上一篇博客的链接&#xff1a;http://t.csdn.cn/2d6fc 接…