【快速入门】MyBatis
一.基础操作
1.准备工作
1)引入依赖
一个是mysql驱动包,一个是mybatis的依赖包:
<dependency><groupId>org.mybatis.spring.boot</groupId><artifactId>mybatis-spring-boot-starter</artifactId><version>3.0.4</version>
</dependency><dependency><groupId>com.mysql</groupId><artifactId>mysql-connector-j</artifactId><scope>runtime</scope>
</dependency>
如果创建项目后,项目中自带着就不用引入了。
2)配置文件
数据库连接配置:
spring:datasource:url: jdbc:mysql://127.0.0.1:3306/mybatis_test?characterEncoding=utf8&useSSL=falseusername: rootpassword: 123456driver-class-name: com.mysql.cj.jdbc.Driver
上面的username和password要根据自己的数据库进行修改。

这个是我们要用的数据库的名字,也要根据自己的数据库进行修改。
如果使用mysql是5.x之前的使用的是 com.mysql.jdbc.Driver,如果是大于5.x使用的是 com.mysql.cj.jdbc.Driver。
打印日志配置:
mybatis:configuration:log-impl: org.apache.ibatis.logging.stdout.StdOutImpl
2.查询(select)
对于查询,使用 @Select 这个标签即可完成。
@Select("SQL语句")
举个例子,我们想要查询 user_info 这个表:
@Select("select * from user_info;")
List<UserInfo> selectAll();@Select("select * from user_info where id=3;")
List<UserInfo> selectById();
此时,selectAll()这个方法就具有了查询 user_info 这个表的功能。
那如果我们想要指定参数,那么要使用 #{参数} :
@Select("select * from user_info where id=#{id};")
List<UserInfo> selectById(Integer id);@Select("select * from user_info where id=#{id} and username = #{username};")
List<UserInfo> selectByIdAndName(String username,Integer id);
我们可以使用 @Param 这个注解对参数进行重命名,但是要保证重命名后的参数必须是重命名:
@Select("select * from user_info where id=#{userId};")
List<UserInfo> selectByIdAndName1(@Param("userId") Integer id);
这里要注意一件事,只有数据库的字段与Java中的对象属性相同时才能进行赋值,那如果不同怎么办呢?
1)别名查询
从SQL语句入手,我们将字段与属性名不同的起一个别名
@Select("select user_name as username from user_info ;")
List<UserInfo> selectAll1();
这样,即使数据库字段是user_name也会成功查询。
2)结果映射
使用 @Results 注解
@Results(id = "BaseMap",value = {@Result(column = "user_name",property = "userName"),@Result(column = "create_time",property = "createTime"),@Result(column = "update_time",property = "updateTime")
})
@Select("select * from user_info;")
List<UserInfo> selectAll();
3)驼峰自动转换
数据库使用蛇形命名法,Java中使用驼峰命名法,通过配置可以两种命名进行自动映射,但是要注意,一定要遵从上述的命名方法,不遵从也不好使。
mybatis:configuration: map-underscore-to-camel-case: true #配置驼峰⾃动转换
3.插入(insert)
插入操作使用 @Insert 注解,用法与查询的大差不差,重复的内容就不过多介绍了:
@Insert("insert into user_info(username,`password`) values(#{username},#{password});")
Integer insertUser(UserInfo userInfo);@Insert("insert into user_info(username,`password`,age) values(#{userInfo.username},#{userInfo.password},#{userInfo.age});")
Integer insertUser(@Param("userInfo") UserInfo userInf);
insertUser返回的Integer是收影响的行数。
这里要注意重命名那里要使用 参数.属性 来获取。
如果我们想要获取主键,执行完SQL语句后,使用userInf.getId()是获取不到的。要使用Options注解:
@Options(useGeneratedKeys = true,keyProperty = "id")
@Insert("insert into user_info(username,`password`,age) values(#{username},#{password},#{age});")
Integer insertUser(UserInfo userInfo);
4.删除(delete)
这个注解是什么应该不难猜了,@Delete。
@Delete("delete from user_info where id=#{id}")
Integer deleteUser(Integer id);
5.更新(update)
注解 @Update,其他与上面的注解都一样。
@Update("update user_info set phone=#{phone} where id=#{id}")
Integer updateUser(Integer phone,Integer id);
二.XML配置文件
1.准备工作
1)配置文件
spring:datasource:url: jdbc:mysql://127.0.0.1:3306/mybatis_test?characterEncoding=utf8&useSSL=falseusername: rootpassword: 123456driver-class-name: com.mysql.cj.jdbc.Driver
mybatis:mapper-locations: classpath:mapper/**Mapper.xml
注意后面的 **Mapper ,这个要根据实际情况写,这个的意思是以 Mapper 为后缀。如果我们写的xml文件的后缀不是 Mapper ,那么要改成与xml文件名相同。
2)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="***********"></mapper>
上面******这些要填的是实现Mapper的类的路径,即全包名+类名。
2.查询(select)
接口中的方法:
List<UserInfo> selectAll();
List<UserInfo> selectById(Integer id);
在xml文件中写:
<select id="selectAll" resultType="com.springdemo.model.UserInfo">select * from user_info;
</select>
<select id="selectById" resultType="com.springdemo.model.UserInfo">select * from user_info where id = #{id};
</select>
id是与对应接口的方法的名称是一样的,resultType是返回的数据类型。
使用xml文件的方法仍然存在数据库字段与对象属性不同的无法赋值的情况,处理方法与注解的一样,都是三种,其中别名查询和配置文件这两个处理方法相同,这里说一下不同的结果映射。
<resultMap id="BaseMap" type="com.springdemo.model.UserInfo"><id column="id" property="id"></id><result column="create_time" property="createTime"></result><result column="update_time" property="updateTime"></result>
</resultMap>
<select id="selectAll" resultMap="BaseMap">select * from user_info;
</select>
在resultMap结构中,id是主键,result中的column是数据库字段名,property是对象属性名。
3.插入(insert)
xml文件:
<insert id="insertUser">insert into user_info(username,`password`,age) values(#{username},#{password},#{age});
</insert>
返回主键:
<insert id="insertUser" useGeneratedKeys="true" keyProperty="id">insert into user_info(username,`password`,age) values(#{username},#{password},#{age});
</insert>
从这里我们也能发现:其实这些代码都是重复的,就换个词,包括重命名啥的,本质上没有变化,下面只是简单的给出xml文件代码。
4.删除(delete)
<delete id="deleteUser">delete from user_info where id=#{id};
</delete>
5.更新(update)
<update id="updateUser">update user_info set phone=#{phone} where id=#{id};
</update>
三.${}与#{}
1.区别
前面一直使用的是#{},那${}是什么。
在实际使用上,我们仅通过看是看不出什么区别的,用是一样用,但是得到的结果是不同的。
@Select("select * from user_info where username=#{name}")
//@Select("select * from user_info where username=${name}")
List<UserInfo> selectByName(String name);
分别运行上面的两个注解,得到下面的运行结果:
#{}的正常:

${}的报错了:

报错提示是SQL写错了。
${}写的SQL语句,我们写的参数是直接拼接上的,username直接等于了lisi,lisi应该是一个字符串,不应该直接拼上去,要加上''。#{}是通过占位符的方法
我们这样修改上面的注解就可以了:
@Select("select * from user_info where username='${name}'")
List<UserInfo> selectByName(String name);

但是这又引出了一个新的问题,SQL注入。
由于使用${}是直接拼接上的,那么完全可以实现SQL注入,因此使用${}的时候就要注意SQL注入问题。
所以,相对${},#{}可谓是优势满满:
1)性能更高,#{}是预编译SQL,其在编译一次后会缓存,下次再次执行的时候就不用编译了;
2)没有SQL注入,更加安全;
那${}真的一无是处吗?存在即合理,要是一点用没有早删了。
2.${}应用
举一个例子,在某些场景下,我们需要对某一数据进行排序查询。先简单写一个查询排序:
select * from standings order by chinese DESC
desc是降序,asc是升序。
从上面的例子可以看到,desc是没加 ' ' 的。如果我们使用#{},势必会加上 ' ' 。这个时候我们就使用${},可以通过直接拼接来实现。但是也要注意SQL注入问题。
再举一个例子,我们要对表进行模糊匹配查询,简单写一个模糊匹配查询:
@Select("select name from standings where name like '${name}%'")
上面的?可以填入任意参数,如果我们使用#{},那么就无法将%给包进去,使用${}就可以。但是这个也有SQL注入问题,我们在实际开发中使用的是mysql内置函数concat来处理:
@Select("select name from standings where name like concat(${name},'%')")
还有一个场景是我们写的SQL要传入参数名,这个时候也要使用${},不能使用#{}。
四.动态SQL
在某些场景,我们传入的字段不是固定的。比如在用户填写个人信息的时候,有一些是必填的,有一些呢可以默认,有一些可以不填。我们在写代码的时候难道要给每一种情况都写一个方法吗?当然不是,这其实就是动态SQL干的事了。
动态SQL可以动态的完成SQL拼接。
1.<if>标签
这个标签就可以动态的填入那些不确定的字段。这个是写在XML文件中的:
<insert id="insertUser">insert into user_info(username,`password`,<if test="gender!=null">gender,</if>age)values(#{username},#{password},<if test="gender!=null">#{gender},</if>#{age})
</insert>
那用注解的方法呢?
用注解写的比较难看,具体写法就是使用<script></script>将上面写的XML语句写在标签中。
下面的各个命名一定要分清,属性名一定要与我们定义的类中的名相同,别乱写,字段名就是数据库中的数据名称。

2.<trim>标签
有这么一种情况,我们要将最前面的一个参数设成不确定参数。如果第一个参数不填,那么就会出现错误,即多出一个 ,
<insert id="insertUser">insert into user_info(<if test="gender!=null">gender</if> ,username,`password`,age)values(<if test="gender!=null">#{gender}</if> ,#{username},#{password},#{age})
</insert>
面对这种问题,我们可以使用<trim>标签来添加和去除前后缀:
<insert id="insertUser">insert into user_info<trim prefix="(" suffix=")" prefixOverrides=","><if test="gender!=null">gender</if>,username,`password`,age</trim> values<trim prefix="(" suffix=")" prefixOverrides=","><if test="gender!=null">#{gender}</if>,#{username},#{password},#{age}</trim>
</insert>
| prefix | 整个语句块以prefix的值作为前缀 |
| suffix | 整个语句块以suffix的值作为后缀 |
| prefixOverrides | 整个语句块要去除的前缀 |
| suffixOverrides | 整个语句块要去除的后缀 |
3.<where>标签
这种用于在使用where的时候,我们要动态的插入where中的条件:
<select id="selectByIdAndName" resultType="com.springdemo.model.UserInfo">select * from user_info<where><if test="id!=null">and id=#{id}</if><if test="username!=null">and username = #{username}</if></where>
</select>
where标签会自动帮我们去除掉多余的 and 或 or
4.<set>标签
这种用于更新(update)数据的时候,我们要动态的传入数据:
<update id="updateUser">update user_info<set><if test="phone!=null">phone=#{phone},</if><if test="gender!=null">gender=#{gender},</if></set>>where id=#{id};
</update>
set标签会自动去除掉多余的,
5.<foreach>标签
这种用于遍历集合。比如我们想要根据一个List集合去删除对应id的用户,我们可以使用foreach标签去遍历每一个id:
<delete id="deleteUser">delete from user_info where id in <foreach collection="idList" item="id" separator="," open="(" close=")">#{id}</foreach>
</delete>
| collection | 绑定方法参数中的集合 |
| item | 遍历时的每一个对象 |
| open | 语句块开头的字符串 |
| close | 语句块结束的字符串 |
| separator | 每次遍历之间间隔的字符串 |
6.<include>标签
主要用于处理冗余重复的片段。
我们使用<sql>标签定义可重定向的sql片段,<include>标签来获取<sql>中的片段。
<sql id="allColumn">id,name,age
</sql>>
<select id="selectById" resultType="com.gdut.springdemo08.model.UserInfo">select<include refid="allColumn"></include>from user_info where id = #{id};
</select>相关文章:
【快速入门】MyBatis
一.基础操作 1.准备工作 1)引入依赖 一个是mysql驱动包,一个是mybatis的依赖包: <dependency><groupId>org.mybatis.spring.boot</groupId><artifactId>mybatis-spring-boot-starter</artifactId><vers…...
提升 React 应用性能:使用 React Profiler 进行性能调优
前言 在现代前端开发中,性能优化是一个不可忽视的重要环节。在 React 生态系统中,React Profiler 是一个强大的工具,它可以帮助我们检测和优化应用的性能。 本文将通过通俗易懂的语言介绍 React Profiler 的作用,并展示如何使用它…...
八、Prometheus 静态配置(Static Configuration)
所有的配置都可以用静态配置来监控,只不过用servicemonitor简单,但是域名需要静态配置 如果使用 Prometheus 静态配置(Static Configuration),确实不需要 ServiceMonitor、Service 和 Endpoints,但这也意味着失去了 Kubernetes 自动发现(Service Discovery, SD) 的能力…...
重生之我在学Vue--第16天 Vue 3 插件开发
重生之我在学Vue–第16天 Vue 3 插件开发 文章目录 重生之我在学Vue--第16天 Vue 3 插件开发前言一、插件的作用与开发思路1.1 插件能做什么?1.2 插件开发四部曲 二、开发全局通知插件2.1 插件基础结构2.2 完整插件代码(带注释解析)2.3 样式文…...
网络VLAN技术详解:原理、类型与实战配置
网络VLAN技术详解:原理、类型与实战配置 1. 什么是VLAN? VLAN(Virtual Local Area Network,虚拟局域网) 是一种通过逻辑划分而非物理连接隔离网络设备的技术。它允许管理员将同一物理网络中的设备划分为多个独立的广播…...
使用自动导入后,eslint报错 eslint9
前提:使用pnpm create vuelatest创建vue应用,并且在创建项目时就勾选eslint和prettier,不然有些配置还需要手动配,比如解决eslint和prettier的冲突问题 1. 解决使用自动导入后Eslint报错问题 配置vite.config.ts // 自动导入api…...
高德爬取瓦片和vue2使用
1、渲染瓦片地址 <template><div class"command-center"><div id"mapContainer" ref"map" class"mapContainer"/></div> </template><script> import Vue from vue import L from leaflet expor…...
交互式可视化进阶(Plotly Dash构建疫情仪表盘)
这里写目录标题 交互式可视化进阶(Plotly Dash构建疫情仪表盘)1. 引言2. 项目背景与意义3. 数据集生成与介绍4. GPU加速在数据处理中的应用5. 交互式仪表盘构建与Plotly Dash6. PyQt GUI集成与美化7. 工程整体架构8. 部分代码实现9. 代码自查与BUG排查10. 总结与展望交互式可…...
如何选择适合您智能家居解决方案的通信协议?
如何选择适合您智能家居解决方案的通信协议? 在开发智能家居产品时,选择合适的通信协议对于设备的高效运行及其在智能家居系统中的互操作性至关重要。市面上协议众多,了解它们的特性并在做决定前考虑各种因素是非常必要的。以下是一些帮助您…...
如何实现Spring Boot与Oracle数据库的完美对接?
想要在Spring Boot项目中使用Oracle数据库?这可不是一件难事!接下来,我将带你一步步走过这个过程,从环境准备到配置,再到实际操作,确保你能够轻松对接Oracle数据库。 环境准备 首先,确保你已经…...
RabbitMQ可靠性进制
文章目录 1.生产者可靠性生产者重连生产者确认小结 2. MQ的可靠性数据持久化LazyQueue小结 3. 消费者的可靠性消费者确认机制消费者失败处理方案业务幂等性唯一消息ID业务判断 兜底方案业务判断 兜底方案 1.生产者可靠性 生产者重连 在某些场景下由于网络波动,可能…...
版本控制器Git(5)
文章目录 前言一、理解标签二、创建标签三、操作标签四、多人协作场景一五、多人协作场景二总结 前言 本篇是最后一篇,主要介绍标签管理有关的内容 一、理解标签 标签定义:在Git中,标签(tag)是对某次提交(c…...
Unity引擎架构介绍及代码示例
Unity是一款跨平台的游戏开发引擎,其强大的功能和灵活的架构使得它成为众多游戏开发者的首选。本文将详细介绍Unity引擎的架构,并通过代码示例展示其在实际开发中的应用。 一、Unity引擎架构概述 Unity引擎的架构可以分为以下几个主要部分: 1…...
【数据分析】读取文件
3. 读取指定列 针对只需要读取数据中的某一列或多列的情况,pd.read_csv()函数提供了一个参数:usecols,将包含对应的columns的列表传入该参数即可。 上面,我们学习了读取 "payment" 和 "items_count" 这…...
Dify使用部署与应用实践
最近在研究AI Agent,发现大家都在用Dify,但Dify部署起来总是面临各种问题,而且我在部署和应用测试过程中也都遇到了,因此记录如下,供大家参考。Dify总体来说比较灵活,扩展性比较强,适合基于它做…...
Java 大视界 -- 基于 Java 的大数据机器学习模型的迁移学习应用与实践(129)
💖亲爱的朋友们,热烈欢迎来到 青云交的博客!能与诸位在此相逢,我倍感荣幸。在这飞速更迭的时代,我们都渴望一方心灵净土,而 我的博客 正是这样温暖的所在。这里为你呈上趣味与实用兼具的知识,也…...
1.Windows+vscode+cline+MCP配置
文章目录 1.简介与资源2.在windows中安装vscode及Cline插件1. 安装vscode2. 安装Cline插件3. 配置大语言模型3. 配置MCP步骤(windows) 1.简介与资源 MCP官方开源仓库 MCP合集网站 参考视频 2.在windows中安装vscode及Cline插件 1. 安装vscode 2. 安装Cline插件 Cline插件…...
C#的字符串之String类与StringBuilder类区别于适用场景
一、分清楚值类型与引用类型 正确理解值类型与引用类型,可以更好的帮助软件开发人员写出性能更好且正确稳定运行的程序: C#值类型与引用类型区别 区别值类型引用类型定义所有继承自【System.ValueType】类型的都是值类型(valueType继承自Sys…...
关于WPS的Excel点击单元格打开别的文档的两种方法的探究【为单元格添加超链接】
问题需求 目录和文件结构如下: E:\Dir_Level1 │ Level1.txt │ └─Dir_Level2│ Level2.txt│ master.xlsx│└─Dir_Level3Level3.txt现在要在master.xlsx点击单元格进而访问Level1.txt、Level2.txt、Level3.txt这些文件。 方法一:“单元格右键…...
conda的基本使用及pycharm里设置conda环境
创建conda环境 conda create --name your_env_name python3.8 把your_env_name换成实际的conda环境名称,python后边的根据自己的需要,选择python的版本。 激活conda环境 conda activate your_env_name 安装相关的包、库 conda install package_name …...
计算机网络-网络规划与设计
基本流程 需求分析—》通信规范分析—》逻辑网络设计—》物理网络设计—》实施阶段 需求分析: 确定需求,包括:业务需求、用户需求、应用需求、计算机平台需求、网络通信需求等。 产物:需求规范 通信规范分析: 现有…...
【QA】建造者模式在Qt有哪些应用
#设计模式 #Qt 一、QDomDocument(XML 文档构建) 模式角色: Builder:QDomDocument 本身Product:XML 文档对象Director:用户代码通过 QDomDocument 逐步构建文档结构 示例代码: QDomDocument…...
六种最新优化算法(TOC、MSO、AE、DOA、GOA、OX)求解多个无人机协同路径规划(可以自定义无人机数量及起始点),MATLAB代码
一、算法简介 (一)阿尔法进化(Alpha Evolution,AE)算法 阿尔法进化(Alpha Evolution,AE)算法是2024年提出的一种新型进化算法,其核心在于通过自适应基向量和随机步长的…...
练习-依依的询问最小值(前缀和差分)
问题描述 依依有个长度为 n 的序列 a,下标从 1 开始。 她有 m 次查询操作,每次她会查询下标区间在[li,ri] 的 a 中元素和。她想知道你可以重新排序序列 a,使得这 m 次查询的总和最小。 求你求出 m 次查询总和的最小值。 输入格式 第…...
ctfshow web刷题记录
RCE 第一题 eval代码执行 : 1、使用system 加通配符过滤 ?csystem("tac%20fl*") ; 2、反字节执行 xxx %20 echo 反字节 3、变量转移 重新定义一个变量 让他代替我们执行 4、伪协议玩法 ?cinclude$_GET[1]?>&1php://filter/readc…...
MySQL单表查询大全【SELECT】
山再高,往上攀,总能登顶;路再长,走下去,定能到达。 Mysql中Select 的用法 ------前言------【SELECT】0.【准备工作】0.1 创建一个库0.2 库中创建表0.3 表中加入一些数据 1.【查询全部】2.【查询指定列】2.1查询指定列…...
考研系列-408真题计算机网络篇(18-23)
写在前面 此文章是本人在备考过程中408真题计算机网络部分(2018年-2023年)的易错题及相应的知识点整理,后期复习也常常用到,对于知识提炼归纳理解起到了很大的作用,分享出来希望帮助到大家~ # 2018 1.停止-等待协议的…...
卷积神经网络(CNN)之 EfficientNet
在深度学习领域,模型的计算效率与性能之间的平衡一直是一个核心挑战。随着卷积神经网络(CNN)在图像分类、目标检测等任务中取得显著成果,模型的复杂度和计算需求也急剧增加。2019年,Google Research 提出的 EfficientN…...
【eNSP实战】将路由器配置为DHCP服务器
拓图 要求: 为 office100 和 office200 分别配置地址池 AR1接口配置 interface GigabitEthernet0/0/0ip address 192.168.100.1 255.255.255.0 # interface GigabitEthernet0/0/1ip address 192.168.200.1 255.255.255.0 AR1路由器上创建office100地址池 [AR1…...
工程化与框架系列(35)--前端微服务架构实践
前端微服务架构实践 🏗️ 引言 随着前端应用规模的不断扩大,微服务架构在前端领域的应用越来越广泛。本文将深入探讨前端微服务架构的实现方案、最佳实践和相关工具。 微服务架构概述 前端微服务架构主要包括以下方面: 应用拆分…...
