MyBatis入门:快速搭建数据库操作框架 + 增删改查(CRUD)
一、创建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=falseusername: root #数据库用户password: root #密码driver-class-name: com.mysql.cj.jdbc.Driver# 设置 Mybatis 的 xml 保存路径
mybatis: mapper-locations: classpath:mapper/*Mapper.xmlconfiguration: # 配置打印 MyBatis 执行的 SQLlog-impl: org.apache.ibatis.logging.stdout.StdOutImplmap-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 {@Autowiredprivate UserInfoMapper userInfoMapper;@Testvoid 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 {@Autowiredprivate UserInfoMapper userInfoMapper;@Testvoid 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 {@Autowiredprivate UserInfoMapper userInfoMapper;@Testvoid 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.xmlconfiguration: # 配置打印 MyBatis 执行的 SQLlog-impl: org.apache.ibatis.logging.stdout.StdOutImplmap-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 {@Autowiredprivate UserInfoMapper userInfoMapper;@Testvoid 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 {@Autowiredprivate UserInfoMapper userInfoMapper;@Testvoid 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 {@Autowiredprivate UserInfoMapper userInfoMapper;@Testvoid 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 {@Autowiredprivate UserInfoMapper userInfoMapper;@Testvoid 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);
}
修改前:
修改后 :
三、报错信息
看到这样的报错“密码错误”,直接去看配置信息
数据库返回结构太多,方法定义的返回结果不匹配
标签参数和方法参数不匹配
相关文章:

MyBatis入门:快速搭建数据库操作框架 + 增删改查(CRUD)
一、创建Mybatis的项目 Mybatis 是⼀个持久层框架, 具体的数据存储和数据操作还是在MySQL中操作的, 所以需要添加MySQL驱动 1.添加依赖 或者 手动添加依赖 <!--Mybatis 依赖包--><dependency><groupId>org.mybatis.spring.boot</groupId><artifactI…...

离线安装Microsoft 照片【笔记】
实验环境为:Windows 10 企业版 LTSC。 1.下载好相关离线依赖包和安装包。 2.管理员身份运行powershell,输入以下命令行: Add-AppPackage .\Microsoft.UI.Xaml.2.4_2.42007.9001.0_x64__8wekyb3d8bbwe.Appx Add-AppPackage .\Microsoft.NET…...
地理卷积神经网络加权回归模型的详细实现方案
以下为地理卷积神经网络加权回归模型的详细实现方案。由于篇幅限制,代码和说明将分模块呈现。 地理卷积神经网络加权回归模型实现 目录 理论基础数据预处理模型架构设计空间权重矩阵生成混合模型实现实验与结果分析优化与扩展结论一、理论基础 1.1 地理加权回归(GWR) 地理…...

【后端高阶面经:Elasticsearch篇】39、Elasticsearch 查询性能优化:分页、冷热分离与 JVM 调优
一、索引设计优化:构建高效查询的基石 (一)分片与副本的黄金配置 1. 分片数量计算模型 # 分片数计算公式(单分片建议30-50GB) def calculate_shards(total_data_gb, single_shard_gb=30):return max...
光伏电站及时巡检:守护清洁能源的“生命线”
在“双碳”目标驱动下,光伏电站作为清洁能源的主力军,正以年均20%以上的装机增速重塑全球能源格局。然而,这些遍布荒漠、屋顶的“光伏矩阵”并非一劳永逸的能源提款机,其稳定运行高度依赖精细化的巡检维护。山东枣庄触电事故、衢州…...

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

软考 系统架构设计师系列知识点之杂项集萃(69)
接前一篇文章:软考 系统架构设计师系列知识点之杂项集萃(68) 第114题 若对关系R(A,B,C,D)和S(C,D,E)进行关系代数运算,则表达式 与()等价。 A.…...
从源码编译支持ffmpeg(H264编码)的opencv(创建mp4视频报错:H264 is not supported with codec id 28)
目录 步骤 1:安装 FFmpeg 在 Ubuntu 上安装 FFmpeg 在 Windows 上安装 FFmpeg 验证FFmpeg是否支持H264编码 步骤 3:克隆 OpenCV 源码 步骤 4:编译 步骤 5:验证安装 本人的配置如下: 系统:Ubuntu 18…...

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 代码: /*** Definition for singly-linked l…...
每日leetcode(昨天赶飞机没做,今天补)
896. 单调数列 - 力扣(LeetCode) 题目 如果数组是单调递增或单调递减的,那么它是 单调 的。 如果对于所有 i < j,nums[i] < nums[j],那么数组 nums 是单调递增的。 如果对于所有 i < j,nums[i]…...
SDL2常用函数:SDL_BlitSurfaceSDL_UpdateWindowSurface 数据结构及使用介绍
SDL_BlitSurface SDL_BlitSurface 是 SDL 1.2/2.0 中都存在的函数,用于将一个表面(Surface)的内容复制到另一个表面,支持部分复制、格式转换和简单的混合操作。 核心功能 表面复制:将源表面的像素数据复制到目标表面区域选择:可…...

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

万亿参数背后的算力密码:大模型训练的分布式架构与自动化运维全解析
目录 一、技术融合的时代背景 二、深度学习在 AI 大模型中的核心作用 2.1 预训练与微调机制 2.2 多模态深度学习的突破 三、分布式计算:大模型训练的基础设施 3.1 分布式训练核心原理 3.2 数据并行实战(PyTorch DDP) 3.3 模型并行与混…...
LangChain03-图数据库与LangGraph
图数据库与LangGraph集成实践 1. 引言 在构建智能问答系统、推荐引擎或复杂决策流程时,传统的关系型数据库和向量数据库往往难以满足对实体关系建模和多跳推理的需求。图数据库(如 Neo4j、TigerGraph)通过节点-边-属性的结构化表示ÿ…...
rabbitmq单机多实例部署
RabbitMQ 单实例部署 单实例部署是指在一台服务器上运行一个 RabbitMQ 实例。这种部署方式适用于小型应用或开发环境,配置简单,资源占用较少。单实例部署的核心是安装 RabbitMQ 并启动服务,通常需要配置 Erlang 环境,因为 RabbitMQ 是基于 Erlang 编写的。单实例部署的优势…...

Linux10正式版发布,拥抱AI了!
📢📢📢📣📣📣 作者:IT邦德 中国DBA联盟(ACDU)成员,10余年DBA工作经验 Oracle、PostgreSQL ACE CSDN博客专家及B站知名UP主,全网粉丝10万 擅长主流Oracle、MySQL、PG、高斯…...

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

全能邮箱全能邮箱:实现邮件管理的自动化!
全能邮箱全能邮箱:实现邮件管理的自动化! 全能邮箱全能邮箱的配置教程?如何注册烽火域名邮箱? 全能邮箱全能邮箱作为一种创新的邮件管理解决方案,正逐渐改变我们处理邮件的方式。蜂邮EDM将围绕全能邮箱全能邮箱&…...
[特殊字符] Linux 日志查看与分析常用命令全攻略
在日常运维与开发排查中,我们经常需要查看服务日志来定位问题。本文系统整理了几种常用的日志查看命令,包括 tail、cat、grep、split、sed 等,并结合实际应用场景,提供了完整的使用方式和示例。 📌 一、tail 命令 ——…...

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

Qt找不到windows API报错:error: LNK2019: 无法解析的外部符号 __imp_OpenClipboard
笔者在开发中出现的bug完整报错如下: spcm_ostools_win.obj:-1: error: LNK2019: 无法解析的外部符号 __imp_OpenClipboard,函数 "void __cdecl spcmdrv::vCopyToClipboard(char const *,unsigned __int64)" (?vCopyToClipboardspcmdrvYAXPE…...
机试 | vector/array Minimum Glutton C++
题目地址 : C - Minimum Glutton #include<stdio.h> #include<iostream> #include<vector> #include<algorithm> using namespace std; int main() {//N:菜肴数,X:总甜度阈值,Y:总咸度阈值int…...

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

前端内容黑白处理、轮播图、奇妙的头像特效
1、内容黑白处理 (1)filter:滤镜 可以把包裹的区域中每一个像素点,经过固定的算法转换成另一种颜色来呈现 (2)grayscale:灰阶滤镜 取值范围:0~1取0:原图去1ÿ…...
蓝桥杯 10. 安全序列
当然可以,以下是整理后的 Markdown 格式题目描述: 题目描述 小蓝是工厂里的安全工程师,他负责安放工厂里的危险品。 工厂是一条直线,直线上有 n 个空位,小蓝需要将若干个油桶放置在这 n 个空位上。每 2 个油桶中间至…...
(10)-java+ selenium->元素之By class name
1.简介 继续介绍WebDriver关于元素定位大法,这篇介绍By ClassName。看到ID,NAME这些方法的讲解,应该知道,要做好Web自动化测试,最好是需要了解一些前端的基本知识。有了前端知识,做元素定位会很轻松,同样写网络爬虫也很有帮助 2.常用定位方法(8种) (1)id (2)nam…...

Git - .gitignore 文件
一、.gitignore 文件介绍 在使用 Git 进行版本控制时,.gitignore 文件是一个非常重要的配置文件,用于告诉 Git 哪些文件或目录不需要被追踪和提交到版本库中。合理使用 .gitignore 文件可以避免提交不必要的文件,如临时文件、编译生成的文件…...
MPI与多线程(如OpenMP)混合编程注意事项与性能优化
文章目录 MPI与多线程(如OpenMP)混合编程注意事项与性能优化混合编程注意事项性能优化策略示例代码编译与运行性能调优建议 MPI与多线程(如OpenMP)混合编程注意事项与性能优化 混合编程注意事项 MPI初始化与线程支持级别: 需要在MPI_Init之前调用MPI_Init_thread指…...
计算机网络学习(八)——MAC
一、MAC 在计算机网络中,MAC(Media Access Control,媒体访问控制)地址是数据链路层的重要概念,它用于唯一标识网络中的设备,并且在局域网(如以太网)中发挥关键作用。 MAC 是硬件地址…...
英语六级-阅读篇
目录 2023年12月大学英语真题(二) 十五选十(Section A) 单词表 短语表 译文 Passage Two(Section C) 单词表 短语表 译文 简介:其实我总结这篇文章就是平时记忆该阅读文章单词中出现的…...