【MyBatis持久层框架】配置文件实现增删改查实战案例(下)

news2024/10/8 21:17:31

前言

前面我们学习了 MyBatis 持久层框架的原生开发方式和 Mapper 代理开发两种方式,解决了使用 JDBC 基础性代码操作数据库时存在的硬编码和操作繁琐的问题。

在配置文件实现增删改查上篇中,我们详细讲解了常用的查询操作,例如查询所有数据,查询数据详情以及使用动态 sql 查询等。文章带来了不错的反馈,并被推荐到热榜,所以继续本系列文章的更新,今天对增删改操作及过程做详细讲解。

  • 【MyBatis持久层框架】配置文件实现的查询操作案例

image-20230130201102997

回顾一下,我们为什么使用 MyBatis 开发呢?前面说过,MyBatis 支持自定义 sql,存储过程以及高级映射,它几乎免除了所有的 JBDC 代码以及设置参数和获取结果集的工作。解决了使用 JBDC 基础性的代码操作数据库时面临的 Java 代码的硬编码和操作繁琐的问题,如图:

本节案例训练目标:能够使用配置文件来实现增删改查操作。

准备工作

今天我们使用MyBatis完成数据库数据的增删改查操作,具体实现如下:

  • 查询数据
    • 查询所有数据
    • 查询数据详情
    • 条件查询
  • 添加数据
  • 修改数据
    • 修改全部字段
    • 修改动态字段
  • 删除数据
    • 单个数据的删除
    • 批量数据的删除

今天的案例是给定一个学生数据表,包括学生id ,姓名,性别,成绩等字段信息,通过MyBatis对数据库中的数据进行增删改操作。

首先,我们要创建好数据库表和添加数据,涉及到的 sql 如下:

drop table if exists student;

create table student(
	id int primary key auto_increment,
	name varchar(10),
	gender char(1),
	score_english int,
	score_math int
);

insert into student(name,gender,score_english,score_math) values
('张三','男',61,65),
('李四','女',45,38),
('王五','男',85,53),
('小王','男',56,58),
('小樊','女',85,92);

数据表如下图:

image-20230129193400530

接下来在 idea中org.chengzi.pojo 包下创建实体类 Student :

public class Student{
    //id 主键
    private int id;
    //学生姓名
    private String name;
    //学生性别
    private String gender;
    //学生英语成绩
    private int scoreEnglish;
    //学生数学成绩
    private int scoreMath;
    
    //这里省略了Getter and Setter方法和重写的Object中的toString方法
}

接下来编写测试用例,这里在 Test 中写单元测试的代码,在测试代码 Java 文件目录下创建 MyBatisTest 类。如图:

image-20230129194459753

为了提高 MyBatis 开发效率,我们再安装 MyBatisX 插件,这个插件主要有两个作用,首先是 XML 映射配置文件和 Mappe r接口的相互跳转,其次是根据 Mapper 接口方法自动生成 statement,如图:

image-20230129194834069

在 File / setting / plugins 中搜索 MyBatisX 插件即可。

其中蓝色图片代表 Mapper 接口文件,红色图标表示 sql 映射配置文件,使用该插件即可在 Mapper 接口中定义方法,在配置文件中自动生成 statement ,在配置文件可快速跳转到对应的 Mapper 接口。这个插件小编认为在 MyBatis 开发中是十分高效的,小编自从学习MyBatis就在使用哦。

添加数据

在客户端中,添加数据是非常常用的需求,用户输入的数据被发送到 Java 代码,Java 代码操作数据库,将数据存入数据表中。在数据库多表关系中,我们有时需要将添加到一张表的数据的主键返回,用与和其他的表建立关系。

例如,在一对多的表关系中,我们在多的一方建立外键关联相关表的主键,此时添加数据并返回之间的操作就是非常需要的,接下来我们先进行添加数据到数据表并通过程序异常处理的方式判断是否添加成功。

我们通过以下步骤完成添加数据的需求:

  • 编写接口方法
    • 参数:除了 id 以外的所有数据,因为id 为主键并设置为自增长
    • 返回值:无
  • 编写 sql 映射配置文件
  • 编写并执行测试方法

编写接口方法

在 StudentMapper 接口中定义添加数据的方法:

/*
添加数据到数据库表
*/
void add(Student student);

编写sql语句

在 sql 映射配置文件中编写对应的 sql 语句,该文件和 Mapper 接口文件位于同一文件目录下,并且 id 的值与 Mapper 接口中定义的对应方法名一致。

<insert id="add">
     insert into student (name, gender, score_english, score_math)
     values (#{name}, #{gender}, #{scoreEnglish}, #{scoreMath})
</insert>

编写测试方法

按照往常的方法,Java 代码中接收到用户数据的数据,并将其封装在 Student 类对象中,将该对象作为参数传递给 add() 方法,如下:

public class MyBatisTest {
    @Test
    public void testAdd() throws IOException {
        //接收参数
        String name="小美";
        String gender="女";
        int scoreEnglish=100;
        int scoreMath=100;

        //封装对象
        Student student = new Student();
        student.setName(name);
        student.setGender(gender);
        student.setScoreEnglish(scoreEnglish);
        student.setScoreMath(scoreMath);

        //1. 获取SqlSessionFactory
        String resource = "mybatis-config.xml";
        InputStream inputStream = Resources.getResourceAsStream(resource);
        SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);

        //2. 获取SqlSession对象
        SqlSession sqlSession = sqlSessionFactory.openSession();

        //3. 获取Mapper接口的代理对象
        StudentMapper studentMapper = sqlSession.getMapper(StudentMapper.class);

        //4. 执行方法
        studentMapper.add(student);

        //5. 释放资源
        sqlSession.close();
    }
}

此时程序运行成功数据也被成功的封装在对象中,但是查看数据库发现数据并没有被成功添加,查看控制台日志信息不难发现,数据虽然操作成功,但是MyBatis默认关闭了事务自动提交,即开启了事务,在操作完成以后,数据库回滚事务,所以到导致数据并没有添加到数据库,如图:

image-20230130210409604

我们只需要在数据添加操作完场以后设置提交事务便可以解决这个问题。如下:

//4. 执行方法
studentMapper.add(student);
sqlSession.commit();

解决方法2,在获取 SqlSession 对象时往 openSession() 方法中传入 true ,表示自动提交事务即不开启事务。如下:

SqlSession sqlSession = sqlSessionFactory.openSession(true);

此时执行程序以后数据添加成功。

这里设置主键id 自增长不用手动添加数据,在 MySQL 中,即使发生了事务回滚等问题,id 自增长也会发生并被占用。例如第一次添加 id=5 的记录发生了事务回滚,下一次添加时 id = 6。

主键返回问题

前面说到,在数据添加成功以后,有时需要返回主键的信息,安装上面的方法,add 方法返回值为 void ,其实,即使你添加返回值为 int 的add() 方法,此时主键也不能正常返回,MyBatis 提供了解决这个问题的办法。

解决这个问题,只需要在sql映射配置文件中修改 statement ,如下:

<insert id="add" useGeneratedKeys="true" keyProperty="id">
    insert into student (name, gender, score_english, score_math)
    values (#{name}, #{gender}, #{scoreEnglish}, #{scoreMath})
</insert>

其中,useGeneratedKeys 属性表示可以获取自增长的主键值,获取的属性封装在 keyProperty 属性中。

修改

用户有时需要根据需求修改数据,用户提交输入发送给 Java 代码,Java 操作数据库修改数据,但是用户可能不会一次修改所有字段的值,此时就需要对用户的输入进行判断。

我们按照一下的步骤完成需求:

  • 编写接口方法
    • 参数:所有要修改的值
    • 返回值:无
  • 编写 sql 语句
  • 编写测试案例并执行

接下来演示根据用户的id 修改该用户的信息。

编写接口方法

在 StudentMapper 接口中添加修改数据的方法,如下:

void update(Map map);

编写SQL语句

在 sql 映射配置文件中编写修改数据的 statement 。如下:

<update id="update">
    update student
    <set>
        <if test="name !=null and name !=''">
            name= #{name},
        </if>
        <if test="gender !=null and gender !=''">
            gender= #{gender},
        </if>
        <if test="scoreEnglish!=null">
            score_english= #{scoreEnglish},
        </if>
      <if test="scoreMath!=null">
          score_math= #{scoreMath}
      </if>
    </set>
           where id=#{id}
</update>

由于用户可能不会修改数据表的全部字段,这里 <if> 标签来选择,忽略不更新的列,最后拼 sql 字符串。<set> 标签用于替代 set 关键字,如果后面的数据不存在,则会自动去掉 ,

编写测试方法

在 MyBatisTest 中编写单元测试的方法,如下:

    @Test
    public void testUpdate() throws IOException {
        //接收参数
        int id=1;
        String name="小美";
        String gender="女";
        int scoreEnglish=100;
        int scoreMath=100;

        //封装对象
        Map map=new HashMap();
        map.put("id",id);
        map.put("name",name);
        map.put("gender",gender);
//      map.put("scoreEnglish",scoreEnglish);
//      map.put("scoreMath",scoreMath);
        
        //1. 获取SqlSessionFactory
        String resource = "mybatis-config.xml";
        InputStream inputStream = Resources.getResourceAsStream(resource);
        SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);

        //2. 获取SqlSession对象
        SqlSession sqlSession = sqlSessionFactory.openSession();

        //3. 获取Mapper接口的代理对象
        StudentMapper studentMapper = sqlSession.getMapper(StudentMapper.class);

        //4. 执行方法
        studentMapper.update(map);
        sqlSession.commit();
        //5. 释放资源
        sqlSession.close();
    }

如果客户端只发送了 id ,name ,gender 属性到 Java 代码,则 sql 字符串拼接如下,执行程序,此时只有给定数据的字段被修改。

image-20230130224142816

注意!!!建议将 POJO 类中的基本数据类型的数据定义为包装类型,因为在sql 映射配置文件中,在判断修改哪些字段时,我们使用变量是否为 NULL 的方式判断了 Java 代码是否接收到了修改该字段的值,如果没有,则不修改该字段,最后在拼 sql 字符串时,会舍弃这一段 sql 。

当然如果你使用基本数据类型,那么一定要判断是否为0,小编初学时在这里卡住到凌晨两点,什么都别说,当时只想砸掉我的电脑!!!

删除

在客户端中,每行数据都有一个删除选项,当然也可以选择批量删除,一般是通过主键删除,Java 代码接收到主键参数后,会操作数据库删除对应的数据。

删除一行数据

分析方法和前面类似,都是从解决问题的步骤和定义 Mapper 接口中的方法是否需要参数和返回值出发,这里不在赘述。

编写接口方法

在 StudentMapper 接口中编写通过 id 删除一条数据的方法,例如:

void deleteById(int id);

编写SQL语句

在 sql 映射配置文件中编写 sql 语句,例如:

 <delete id="deleteById">
     delete from student where id=#{id};
 </delete>

编写测试方法

在 MyBatisTest 中编写单元测试的方法,执行程序,例如:

   @Test
    public void testDeleteById() throws IOException {
        //接收参数,该id以后需要传递过来
        int id=5;

        //1. 获取SqlSessionFactory
        String resource = "mybatis-config.xml";
        InputStream inputStream = Resources.getResourceAsStream(resource);
        SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);

        //2. 获取SqlSession对象
        SqlSession sqlSession = sqlSessionFactory.openSession(true);

        //3. 获取Mapper接口的代理对象
        StudentMapper studentMapper = sqlSession.getMapper(StudentMapper.class);

        //4. 执行方法
        studentMapper.deleteById(id);

        //5. 释放资源
        sqlSession.close();
    }

注意:设置自动提交事务。

运行结果,此时数据已经从数据表中删除。如图:

image-20230130233905156

批量删除

用户有时有删除多条数据的需求,此时需要删除的数据被发送到 Java 代码中,其每条数据的主键 id 会被封装在数组中,删除数据时遍历数组即可删除数据库中的对应记录。

编写接口方法

在 StudentMapper 接口中定义删除多条数据的方法,如下:

编写SQL语句

在写 sql 语句时,需要考虑遍历数组的方式,MyBatis 提供了增强 for 的形式在 sql 中遍历数组。这里删除的数组中存放的是需要批量删除的数据的主键 id。如下:

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

使用 <foreach>标签,用来迭代任何可迭代的对象,例如数组,集合等,在标签中通常添加以下的属性:

1,collection 属性

在底层中,MyBatis 会将数组参数封装为一个 Map 集合,在集合中默认的键名为 array ,值为数组,即:array = 数组。当然我们也可以使用注解的方式改变 Map 集合中默认的键名。

例如在定义接口方法时使用注解:

void deleteByIds(@Param("ids") int[] ids);

2,item 属性

其变量用来存放本次遍历获取到的数组元素

3,separator 属性

迭代项中间的分隔符,例如上面的 , ,使用 <foreeach> 标签迭代对象时,其不会错误的添加多余的分隔符,例如最后一项不应该添加分隔符。

4,open ,close 属性

这两个属性值拼在拼接 sql 语句之前和最后,均只会拼接一次。例如上面的 in 后面的一对括号就可以使用该属性封装,这样提高了 sql 的可读性并让代码变得整洁。

编写测试方法

在 MyBatisTest 中编写单元测试的方法,如下:

    @Test
    public void testDeleteByIds() throws IOException {
        //接收参数,该id以后需要传递过来
        int[] ids={1,2,3};

        //1. 获取SqlSessionFactory
        String resource = "mybatis-config.xml";
        InputStream inputStream = Resources.getResourceAsStream(resource);
        SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);

        //2. 获取SqlSession对象
        SqlSession sqlSession = sqlSessionFactory.openSession(true);

        //3. 获取Mapper接口的代理对象
        StudentMapper studentMapper = sqlSession.getMapper(StudentMapper.class);

        //4. 执行方法
        studentMapper.deleteByIds(ids);

        //5. 释放资源
        sqlSession.close();
    }

我们批量删除数据库表中的 id 为1,2,3 的三条数据。执行程序,运行结果如图:

此时可以看到,使用标签时,sql语句被拼接为正确的形式,如下:

delete from student where id in ( ? , ? , ? ) ; 

这里也是动态 sql 的一种体现。

总结

我们已经结合实战案例,通过配置文件的方式实现了数据库中数据的增删改查操作。其中,由于现实中操作的需求,我们也讲解了动态 sql 的实现,例如在删除多条数据时就需要使用动态 sql 来实现。不难看出,使用了框架开发以后,不仅代码的可读性变强了,编码的效率也大大提高了。

总的来说,使用配置文件的方式来写 sql 语句,确实比 JDBC 原生代码方便呢很多。其实,在简单的 sql 操作中,我们还会使用注解的方式进行开发。下期见。

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

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

相关文章

Spring Boot 项目 - API 文档搜索引擎

在线体验 : http://43.139.1.94:9090/index.html项目 Gitee 链接 : API 文档搜索引擎1.认识搜索引擎我们平时查百度, 搜狗的时候, 结果页会显示若干条相关结果 , 每个结果几乎都包含图片, 标题, 描述, 展示 URL以及时间等等.1.1 搜索引擎的本质输入一个查询词, 得到若干个结果,…

stm32学习笔记-1 STM32简介

1 STM32简介 [toc] 注&#xff1a;笔记主要参考 江科大自化协 教学视频“STM32入门教程-2023持续更新中”。 注&#xff1a;工程及代码文件放在了本人的Github仓库。 1.1 套件简介 本教程使用STM32最小系统板&#xff08;STM32F103C8T6&#xff09;面包板硬件平台进行学习。…

微信小程序 Springboot校园自动点餐系统带跑腿 java

开发语言&#xff1a;Java 小程序前端框架&#xff1a;uniapp 小程序运行软件&#xff1a;微信开发者 可选运行软件:webapp (hbuiderx) 前端开发语言:vue.js 后端技术:Springboot(SpringSpringMVCMyBatis) 可选技术:springboot 后端开发环境:idea和eclipse都支持 数据库:mysql …

六、服务端开发

服务器端开发&#xff1a;服务器设计框架&#xff1a;缓解和转发的作用连接音箱和app最大一个作用转发一个app操作音箱app绑定音箱服务器类实现&#xff1a;jsoncpplibventverser.h#ifndef SERVER_H #define SERVER_H#include <event.h>#define IP "172.17.7.99&…

【C++入门】缺省参数

目  录1 缺省参数1.1 缺省参数概念1.2 缺省参数分类1.3 缺省参数使用注意1 缺省参数 1.1 缺省参数概念 缺省参数是声明或定义函数时为函数的参数指定一个缺省值。 在调用该函数时&#xff0c;如果没有指定实参&#xff0c;则采用该形参的缺省值&#xff0c;否则使用指定的实…

Spring Profiles 实现多环境配置 ,切换环境

Spring Profiles 实现多环境配置 Spring Profiles 就是针对应用程序&#xff0c;不同环境需要不同配置加载的一种解决方案。 使用场景: 我们平常项目开发&#xff0c;经常需要根据不同的环境进行配置的修改&#xff0c;比如在本地开发会加载本机的配置和开发环境数据库&#x…

【NKOJ-昨天今天和明天】考试游记

目录 昨天上午的序列 - 30pts今天上午的扫除 - 100pts明天上午的教室 - 100pts明天上午的数组 - 100pts明天上午的函数 - 100pts 题目排序太合理了,EDCBA依次变难,导致我对着A题苦思冥想了半小时...但是A题是[LeetCode 907. 子数组的最小值之和]的换皮题(除了题目一点没变)然…

初始OAuth2.0

1. 什么是OAuth2.0 OAuth2.0是目前使用非常广泛的授权机制&#xff0c;用于授权第三方应用获取用户的数据。 举例说明&#xff1a;用户可以通过选择其他登录方式来使用gitee&#xff0c;这里就使用到了第三方认证。 OAuth 引入了一个授权层&#xff0c;用来分离两种不同的角色…

前端工程化

一、前端工程化1、webpack&#xff08;1&#xff09;定义&#xff1a;是一个前端的构建工具。前端代码格式多&#xff08;html、css、js、图片&#xff09;&#xff0c;前端构建工具的作用是将各种格式不同文件打包到一起&#xff0c;方便项目的上线运行。&#xff08;将开发环…

Java学习笔记---干货

Java学习 一、java版本 JavaSE &#xff1a;标准版&#xff08;桌面应用程序、控制台程序&#xff09; JavaEE&#xff1a;E企业级开发&#xff08;Web端&#xff0c;服务器的开发&#xff09; JDK&#xff1a;Java开发工具 JRE&#xff1a;Java运行环境 JVM&#xff1a;…

通信原理笔记—基带信号的功率谱

目录 二进制纯随机序列基带信号的功率谱&#xff1a; 基带信号的功率谱分析&#xff1a; (1)信号(t)的功率谱&#xff1a; (2)信号v(t)的功率谱&#xff1a; 随机序列S(t)的功率谱&#xff1a; 二进制纯随机序列基带信号的功率谱&#xff1a; 基带信号的功率谱分析&#…

软件需求说明书确保正确性的6大关键点

软件需求说明书对软件开发项目非常关键&#xff0c;如何确保其正确性&#xff0c;关键有6大要点&#xff01; 1、需求与其他需求是否相互冲突或重复 一般需求规格说明书长达几百页&#xff0c;并不是一蹴而就的&#xff0c;因此可能出现前后观点的重叠或差异&#xff0c;或同一…

[HDCTF2019]Maze 题解

少欲则心静&#xff0c;心静则事简。 ——人民日报 1.查壳 是一个加了upx壳的32位EXE文件 2.使用Kali Linux脱壳 maze题目脱壳3.去除脏字节 没有找到主函数&#xff0c;发现这段汇编代码标红了&#xff0c;IDA分析崩溃&#xff0c;这是掺杂了花指令 这里jnz&#xff0c;不论判…

中国电子学会2022年03月份青少年软件编程Scratch图形化等级考试试卷三级真题(含答案)

青少年软件编程&#xff08;图形化&#xff09;等级考试试卷&#xff08;三级&#xff09; 分数&#xff1a;100 题数&#xff1a;38 一、单选题(共25题&#xff0c;共50分) 1. 以下四个选项中&#xff0c;运行哪个积木块&#xff0c;可能得到523这个数值&#xff1f;&…

25-35分布式事务seata

分布式事务Seata使用及其原理剖析 Seata的三大角色 TC (Transaction Coordinator) - 事务协调者 维护全局和分支事务的状态&#xff0c;驱动全局事务提交或回滚。 TM (Transaction Manager) - 事务管理器 定义全局事务的范围&#xff1a;开始全局事务、提交或回滚全局事务。 RM…

devicetree和启动参数解析流程

devicetree和启动参数解析流程 文章目录devicetree和启动参数解析流程一、设备树解析概述二、early device tree 解析流程三、device node节点创建流程四、bootargs参数解析&#xff14;.1 bootargs参数配置&#xff14;.&#xff12; early param参数解析&#xff14;.&…

Docker - 2. Docker 工作原理

目录 1. Docker入门图解 2. Docker 整体架构和底层通讯原理 1. Docker入门图解 (1) Docker是一个Client-Server结构的系统&#xff0c;Docker守护进程(图中Docjer daemon)运行在主机上&#xff0c;然后通过Socket链接客户端往返&#xff0c;守护进程从客户端接收命令并管理在…

PySpark 之 SparkSQL 编程

1. DataFrame 的创建 1.1 RDD 和 DataFrame 的区别 RDD 是一种弹性分布式数据集&#xff0c;Spark中的基本抽象。表示一种不可变的、分区储存的集合&#xff0c;可以进行并行操作DataFrame是一种以列对数据进行分组表达的分布式集合&#xff0c; DataFrame等同于Spark SQL中的…

jvm宏观上类的加载机制整体和微观上通过类加载器进行加载的过程

说到一个词“类的加载”其实含有歧义&#xff0c;因为在jvm中可以说有一个宏观的&#xff0c;即整体上的类的加载&#xff0c;还有一个微观上的加载&#xff0c;也就是狭隘的通过类加载器的加载class文件的过程&#xff0c;这里介绍这两种“类的加载”。 类的整体加载过程(类加…

Windows C盘清理的正确方式,从此你告别红色烦恼

前言 伴随着电脑工作的时间越久&#xff0c;C盘常常会提示显示其内存已不足。 C盘容量不足将会极大影响系统的运行速度&#xff0c;电脑会变卡、死机。 今天&#xff0c;就给大家分享一个C盘空间清理终极解决方案&#xff1a; 1、利用Windows自己附带的磁盘清理工具 1&…