MyBatis入门:快速搭建数据库操作框架 + 增删改查(CRUD)

news2025/5/29 10:28:36

一、创建Mybatis的项目

Mybatis 是⼀个持久层框架, 具体的数据存储和数据操作还是在MySQL中操作的, 所以需要添加MySQL驱动

1.添加依赖

或者 手动添加依赖

        <!--Mybatis 依赖包-->
        <dependency>
            <groupId>org.mybatis.spring.boot</groupId>
            <artifactId>mybatis-spring-boot-starter</artifactId>
            <version>3.0.4</version>
        </dependency>
        <!--mysql驱动包-->
        <dependency>
            <groupId>com.mysql</groupId>
            <artifactId>mysql-connector-j</artifactId>
            <scope>runtime</scope>
        </dependency>

项⽬⼯程创建完成后,⾃动在pom.xml⽂件中,导⼊Mybatis依赖和MySQL驱动依赖

版本会随着SpringBoot 版本发⽣变化

SpringBoot 3.X对⽤MyBatis版本为3.X

对应关系参考:Introduction – mybatis-spring-boot-autoconfigure

2.配置常见的数据库信息

这是常见关于Mybatis的配置信息,大家可以自取

csdn暂时还不支持yml文件,这是 yml 文件:

spring:
  datasource:                      # 配置数据库名
    url: jdbc:mysql://127.0.0.1:3306/mybatis_test?characterEncoding=utf8&useSSL=false
    username: root  #数据库用户
    password: root  #密码
    driver-class-name: com.mysql.cj.jdbc.Driver


# 设置 Mybatis 的 xml 保存路径
mybatis:  
  mapper-locations: classpath:mapper/*Mapper.xml
  configuration: # 配置打印 MyBatis 执行的 SQL
    log-impl: org.apache.ibatis.logging.stdout.StdOutImpl
    map-underscore-to-camel-case: true  #自动驼峰转换

前提是有这样的一个数据库

那么这里提供一个数据库:

-- 创建数据库
DROP DATABASE IF EXISTS mybatis_test;

CREATE DATABASE mybatis_test DEFAULT CHARACTER SET utf8mb4;

-- 使用数据数据
USE mybatis_test;

-- 创建表[用户表]
DROP TABLE IF EXISTS user_info;
CREATE TABLE `user_info` (
        `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() ON UPDATE now(),
        PRIMARY KEY ( `id` ) 
) ENGINE = INNODB DEFAULT CHARSET = utf8mb4; 

-- 添加用户信息
INSERT INTO mybatis_test.user_info( username, `password`, age, gender, phone )
VALUES ( 'admin', 'admin', 18, 1, '18612340001' );
INSERT INTO mybatis_test.user_info( username, `password`, age, gender, phone )
VALUES ( 'zhangsan', 'zhangsan', 18, 1, '18612340002' );
INSERT INTO mybatis_test.user_info( username, `password`, age, gender, phone )
VALUES ( 'lisi', 'lisi', 18, 1, '18612340003' );
INSERT INTO mybatis_test.user_info( username, `password`, age, gender, phone )
VALUES ( 'wangwu', 'wangwu', 18, 1, '18612340004' );


-- 创建文章表
DROP TABLE IF EXISTS article_info;
        
CREATE TABLE article_info (
        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 article_info ( title, content, uid ) VALUES ( 'Java', 'Java正文', 1 );

这样一个表

3.写对应的对象

一般写在model文件夹下

@Data
public class UserInfo {

    private Integer id;
    private String username;
    private String password;
    private Integer age;
    private Integer gender;
    private String phone;
    //数据库用下划线连接单词,java直接用小驼峰
    private Integer deleteFlag;
    private Date createTime;
    private Date updateTime;

}

4.写持久层代码

一般写在mapper文件夹下,或者Dao

@Mapper
public interface UserInfoMapper {

    //查询所有用户的信息
    @Select("select * from user_info")
    List<UserInfo> selectAll();
}

5.单元测试

在对应的mapper接口下,右击

@SpringBootTest
class UserInfoMapperTest {

    @Autowired
    private UserInfoMapper userInfoMapper;

    @Test
    void selectAll() {
        userInfoMapper.selectAll().forEach(x -> System.out.println(x));
        //等同于
//        List<UserInfo> userInfos = userInfoMapper.selectAll();
//        for (UserInfo userInfo : userInfos) {
//            System.out.println(userInfo);
//        }
    }
}

结果:

二、Mybatis的基本操作

1.日志打印

2.传递单个参数

通过 #{……} 传递 参数

@Mapper
public interface UserInfoMapper {
    
    //                 只有一个参数的时候这里写什么名字无所谓
    @Select("select * from user_info where id = #{id}")
    UserInfo selectUserById(Integer id);
}

单元测试:

@SpringBootTest
class UserInfoMapperTest {

    @Autowired
    private UserInfoMapper userInfoMapper;

    @Test
    void selectUserById() {
        System.out.println(userInfoMapper.selectUserById(2));
    }
}

结果:

3.传递多个参数

3种方法

方法1:

标签 和 方法 中的名字一样

方法2:

它给方法的每个形参取了别名,例如第一个param1 第二个 param2

方法3:

使用@Param("……"),和 标签中的 #{……}对应

@Mapper
public interface UserInfoMapper {

    //    @Select("select * from user_info where id = #{id} and gender = #{gender}")   方法1    推荐
    //    @Select("select * from user_info where id = #{param2} and gender = #{param1}")  方法2   不推荐
    //    @Select("select * from user_info where id = #{id2} and gender = #{gender2}")  错误
    //
    @Select("select * from user_info where id = #{id2} and gender = #{gender2}") // 方法3   推荐
    List<UserInfo> selectUserByIdAndGender(@Param("id2") Integer id,@Param("gender2") Integer gender);

}

单元测试:

@SpringBootTest
class UserInfoMapperTest {

    @Autowired
    private UserInfoMapper userInfoMapper;

    @Test
    void selectUserByIdAndGender() {
        List<UserInfo> userInfos = userInfoMapper.selectUserByIdAndGender(3, 1);
        System.out.println(userInfos);
    }
}

结果:

返回的参数可以是对象,也可以是集合类:

当我们知道数据库中对应的参数只有一个时,可以用类接收,但是最好用集合,万一他人增加了符号相同条件的数据,一个类就装不下。

4.查(Select)

查询之前已经都写到了,就不再写了。

发现这样的一个问题:

数据库的规范是单词之间用下划线分割,java的变量规范是小驼峰命名。这就导致了属性对应不上导致为null

解决办法,我先讲最推荐的:

4.1 开启驼峰命名

在yml或者properties文件中设置:

# 设置 Mybatis 的 xml 保存路径
mybatis:
  mapper-locations: classpath:mapper/*Mapper.xml
  configuration: # 配置打印 MyBatis 执行的 SQL
    log-impl: org.apache.ibatis.logging.stdout.StdOutImpl
    map-underscore-to-camel-case: true  #自动驼峰转换

4.2 起别名

@Mapper
public interface UserInfoMapper {

    @Select("select id, username, password, age, gender, phone, delete_flag as deleteFlag, " +
            "create_time as createTime, update_time as updateTime from user_info")
    List<UserInfo> selectAll2();

}

即便是不用起别名也不建议用 select *就应该用到哪一列写哪一列,即便是所有的列都需要也这么写,因为更加规范。

4.3 结构映射

4.3.1 @Results 和 @Result
@Mapper
public interface UserInfoMapper {

//    @Select("select id, username, password, age, gender, phone, delete_flag as deleteFlag, " +
//            "create_time as createTime, update_time as updateTime from user_info")
    @Results({
        @Result(column = "delete_flag", property = "deleteFlag"),
        @Result(column = "create_time", property = "createTime"),
        @Result(column = "update_time", property = "updateTime")
    })
    @Select("select id, username, password, age, gender, phone, delete_flag, create_time, update_time from user_info")
    List<UserInfo> selectAll2();
}

这样比起别名麻烦呀,那么真实用法是这样:

4.3.2 @ResultMap

5.增(Insert)

5.1传递对象

方法一:

@Mapper
public interface UserInfoMapper {

    @Insert("insert into user_info (username, `password`, age, gender) values (#{username},#{password},#{age},#{gender})")
    Integer insertUser(UserInfo userInfo);

}

Mapper层

@SpringBootTest
class UserInfoMapperTest {

    @Autowired
    private UserInfoMapper userInfoMapper;

    @Test
    void insertUser() {
        UserInfo userInfo = new UserInfo();
        userInfo.setUsername("张三");
        userInfo.setPassword("123445");
        userInfo.setAge(19);
        userInfo.setGender(0);

        userInfoMapper.insertUser(userInfo);
    }

}

成功:

方法二:

@Mapper
public interface UserInfoMapper {

    @Insert("insert into user_info (username, `password`, age, gender)" +
            "values (#{userInfo.username},#{userInfo.password},#{userInfo.age},#{userInfo.gender})")
    Integer insertUserByParam(@Param("userInfo") UserInfo userInfo);
}
@SpringBootTest
class UserInfoMapperTest {

    @Autowired
    private UserInfoMapper userInfoMapper;


    @Test
    void insertUserByParam() {
        UserInfo userInfo = new UserInfo();
        userInfo.setUsername("李四");
        userInfo.setPassword("jaba213");
        userInfo.setAge(19);
        userInfo.setGender(0);

        userInfoMapper.insertUser(userInfo);
    }
}

6.删(Delete)

删除的时候一般使用id删除

假设我们现在是pdd的员工,我们下单了一个商品但是还没有付钱,那么此时我们就需要拿到这个订单的id,如果在10分钟内不付钱,我们就删除这个订单。

那么我们就需要在插入之后拿到id,可以用这个注解:

6.1 @Options

@Mapper
public interface UserInfoMapper {

    @Delete("delete from user_info where id = #{id}")
    Integer delete(Integer id);

    @Options(useGeneratedKeys = true, keyProperty = "id")
    @Insert("insert into user_info (username, `password`, age, gender)" +
            "values (#{userInfo.username},#{userInfo.password},#{userInfo.age},#{userInfo.gender})")
    Integer insertUserByParam(@Param("userInfo") UserInfo userInfo);

}

单元测试:

@SpringBootTest
class UserInfoMapperTest {

    @Autowired
    private UserInfoMapper userInfoMapper;

    @Test
    void insertUserByParam() {
        UserInfo userInfo = new UserInfo();
        userInfo.setUsername("wangmaz");
        userInfo.setPassword("54231");
        userInfo.setAge(19);
        userInfo.setGender(0);
        //返回影响的行数
        Integer result = userInfoMapper.insertUserByParam(userInfo);
        //                                                  通过getId()获取            
        System.out.println("执行结果" + result + " ,id : " + userInfo.getId());
    }

结果:

那么拿到数据你想用这个id干什么自己处理就好了

普通的删除:

@Mapper
public interface UserInfoMapper {

    @Delete("delete from user_info where id = #{id}")
    Integer delete(Integer id);

}

单元测试:

@SpringBootTest
class UserInfoMapperTest {

    @Autowired
    private UserInfoMapper userInfoMapper;

    @Test
    void delete() {
//    删除id为11的数据
        userInfoMapper.delete(11);
    }
}

运行前:

运行后:

7.改(Update)

@Mapper
public interface UserInfoMapper {


    @Update("update user_info set password = #{password} where id = #{id}")
    Integer update(Integer id, String password);
}
@Mapper
public interface UserInfoMapper {

    @Update("update user_info set password = #{password} where id = #{id}")
    Integer update(Integer id, String password);
}

修改前:

修改后 :

三、报错信息

看到这样的报错“密码错误”,直接去看配置信息

数据库返回结构太多,方法定义的返回结果不匹配

标签参数和方法参数不匹配

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

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

相关文章

离线安装Microsoft 照片【笔记】

实验环境为&#xff1a;Windows 10 企业版 LTSC。 1.下载好相关离线依赖包和安装包。 2.管理员身份运行powershell&#xff0c;输入以下命令行&#xff1a; Add-AppPackage .\Microsoft.UI.Xaml.2.4_2.42007.9001.0_x64__8wekyb3d8bbwe.Appx Add-AppPackage .\Microsoft.NET…

【后端高阶面经:Elasticsearch篇】39、Elasticsearch 查询性能优化:分页、冷热分离与 JVM 调优

一、索引设计优化:构建高效查询的基石 (一)分片与副本的黄金配置 1. 分片数量计算模型 # 分片数计算公式(单分片建议30-50GB) def calculate_shards(total_data_gb, single_shard_gb=30):return max

基于 ZU49DR FPGA 的无线电射频数据采样转换开发平台核心板

无线电射频数据采样转换开发板及配套开发平台的核心板&#xff0c;该SOM核心板是一个最小系统&#xff0c;包括AMD公司的 Zynq UltraScale RFSOC 第3代系列XCZU49DR-2FFVF1760I FPGA、时钟、电源、内存以及 Flash。与其配套的底板是标准的全高全长Gen4.0 x8的PCIE卡&#xff0c…

软考 系统架构设计师系列知识点之杂项集萃(69)

接前一篇文章&#xff1a;软考 系统架构设计师系列知识点之杂项集萃&#xff08;68&#xff09; 第114题 若对关系R(A&#xff0c;B&#xff0c;C&#xff0c;D)和S(C&#xff0c;D&#xff0c;E)进行关系代数运算&#xff0c;则表达式 与&#xff08;&#xff09;等价。 A.…

leetcode 83和84 Remove Duplicates from Sorted List 和leetcode 1836

目录 83. Remove Duplicates from Sorted List 82. Remove Duplicates from Sorted List II 1836. Remove Duplicates From an Unsorted Linked List 删除链表中的结点合集 83. Remove Duplicates from Sorted List 代码&#xff1a; /*** Definition for singly-linked l…

【LeetCode 热题 100】买卖股票的最佳时机 / 跳跃游戏 / 划分字母区间

⭐️个人主页&#xff1a;小羊 ⭐️所属专栏&#xff1a;LeetCode 热题 100 很荣幸您能阅读我的文章&#xff0c;诚请评论指点&#xff0c;欢迎欢迎 ~ 目录 买卖股票的最佳时机跳跃游戏跳跃游戏 II划分字母区间 买卖股票的最佳时机 买卖股票的最佳时机 class Solution { pu…

万亿参数背后的算力密码:大模型训练的分布式架构与自动化运维全解析

目录 一、技术融合的时代背景 二、深度学习在 AI 大模型中的核心作用 2.1 预训练与微调机制 2.2 多模态深度学习的突破 三、分布式计算&#xff1a;大模型训练的基础设施 3.1 分布式训练核心原理 3.2 数据并行实战&#xff08;PyTorch DDP&#xff09; 3.3 模型并行与混…

Linux10正式版发布,拥抱AI了!

&#x1f4e2;&#x1f4e2;&#x1f4e2;&#x1f4e3;&#x1f4e3;&#x1f4e3; 作者&#xff1a;IT邦德 中国DBA联盟(ACDU)成员&#xff0c;10余年DBA工作经验 Oracle、PostgreSQL ACE CSDN博客专家及B站知名UP主&#xff0c;全网粉丝10万 擅长主流Oracle、MySQL、PG、高斯…

在离线 OpenEuler-22.03 服务器上升级 OpenSSH 的完整指南

当然可以&#xff01;以下是一篇结构清晰、语言通俗易懂的技术博客草稿&#xff0c;供你参考和使用&#xff1a; 在离线 OpenEuler-22.03 服务器上升级 OpenSSH 的完整指南 背景介绍 最近在对一台内网的 OpenEuler-22.03 服务器进行安全扫描时&#xff0c;发现其 SSH 版本存在…

全能邮箱全能邮箱:实现邮件管理的自动化!

全能邮箱全能邮箱&#xff1a;实现邮件管理的自动化&#xff01; 全能邮箱全能邮箱的配置教程&#xff1f;如何注册烽火域名邮箱&#xff1f; 全能邮箱全能邮箱作为一种创新的邮件管理解决方案&#xff0c;正逐渐改变我们处理邮件的方式。蜂邮EDM将围绕全能邮箱全能邮箱&…

mysql-tpcc-mysql压测工具使用

在Linux系统上安装和配置tpcc-mysql进行MySQL的TPC-C基准测试&#xff0c;通常涉及以下几个步骤。请注意&#xff0c;由于tpcc-mysql不是一个官方工具&#xff0c;它可能需要从第三方仓库获取&#xff0c;如Percona提供的版本。 前置条件 确保MySQL或MariaDB已安装&#xff1…

Qt找不到windows API报错:error: LNK2019: 无法解析的外部符号 __imp_OpenClipboard

笔者在开发中出现的bug完整报错如下&#xff1a; spcm_ostools_win.obj:-1: error: LNK2019: 无法解析的外部符号 __imp_OpenClipboard&#xff0c;函数 "void __cdecl spcmdrv::vCopyToClipboard(char const *,unsigned __int64)" (?vCopyToClipboardspcmdrvYAXPE…

OpenCv高阶(十七)——dlib库安装、dlib人脸检测

文章目录 前言一、dlib库简介二、dlib库安装1、本地安装&#xff08;离线&#xff09;2、线上安装 三、dlib人脸检测原理1、HOG 特征提取2、 SVM 分类器训练3、 滑动窗口搜索4、非极大值抑制&#xff08;NMS&#xff09; 四、dlib人脸检测代码1、导入OpenCV计算机视觉库和dlib机…

前端内容黑白处理、轮播图、奇妙的头像特效

1、内容黑白处理 &#xff08;1&#xff09;filter&#xff1a;滤镜 可以把包裹的区域中每一个像素点&#xff0c;经过固定的算法转换成另一种颜色来呈现 &#xff08;2&#xff09;grayscale&#xff1a;灰阶滤镜 取值范围&#xff1a;0~1取0&#xff1a;原图去1&#xff…

Git - .gitignore 文件

一、.gitignore 文件介绍 在使用 Git 进行版本控制时&#xff0c;.gitignore 文件是一个非常重要的配置文件&#xff0c;用于告诉 Git 哪些文件或目录不需要被追踪和提交到版本库中。合理使用 .gitignore 文件可以避免提交不必要的文件&#xff0c;如临时文件、编译生成的文件…

如何通过API接口实现自动化上货跨平台铺货?商品采集|商品上传实现详细步骤

一、引言&#xff1a;跨平台铺货的技术挑战与 API 价值 在电商多平台运营时代&#xff0c;商家需要将商品同步上架至淘宝、京东、拼多多、亚马逊、Shopee 等多个平台&#xff0c;传统手动铺货模式存在效率低下&#xff08;单平台单商品上架需 30-60 分钟&#xff09;、数据一致…

《三维点如何映射到图像像素?——相机投影模型详解》

引言 以三维投影介绍大多比较分散&#xff0c;不少小伙伴再面对诸多的坐标系转换中容易弄混&#xff0c;特别是再写代码的时候可能搞错&#xff0c;所有这篇文章帮大家完整的梳理3D视觉中的投影变换的全流程&#xff0c;一文弄清楚这个过程&#xff0c;帮助大家搞清坐标系转换…

零基础设计模式——结构型模式 - 适配器模式

第三部分&#xff1a;结构型模式 - 适配器模式 (Adapter Pattern) 欢迎来到结构型模式的第一站&#xff01;结构型模式关注的是如何将类或对象组合成更大的结构&#xff0c;同时保持结构的灵活性和效率。适配器模式是其中非常实用的一个&#xff0c;它能帮助我们解决接口不兼容…

WordPress多语言插件安装与使用教程

WordPress多语言插件GTranslate的使用方法 在wordpress网站后台搜索多语言插件GTranslate并安装&#xff0c;安装完成、用户插件后开始设置&#xff0c;以下为设置方法&#xff1a; 1、先在后台左侧找到Gtranslate&#xff0c;进入到设置界面 2、选择要显示的形式&#xff0c…

欣佰特科技|SenseGlove Nova2 力反馈数据手套:助力外科手术训练的精准触觉模拟

在医疗科技持续发展的背景下&#xff0c;虚拟现实&#xff08;VR&#xff09;技术正在改变外科手术培训的方式&#xff0c;而 SenseGlove Nova2 力反馈数据手套 在这一领域发挥着重要作用。 SenseGlove Nova2 力反馈数据手套 与 VirtualiSurg 手术模拟系统深度结合。其手部追踪…