ssm-mybatisPlus学习笔记
注意!mybatisPlus只能够进行单表操作,其他的仍需要mybatis
1.快速入门
编写启动类
@MapperScan("com.atguigu.mapper")
@SpringBootApplication
public class MainApplication {public static void main(String[] args) {SpringApplication.run(MainApplication.class,args);}}
编写实体类
@Data
public class User {private Long id;private String name;private Integer age;private String email;
}
编写mapper接口
在mybatis中我们只需要继承一个baseMapper接口就可以了,我们可以看到在baseMapper接口中已经帮你编写好了对应的增删改查的方法,你直接使用就可以了,注意在对应的泛型类接口中写入你想要增删改查的pojo类
public interface UserMapper extends BaseMapper<User> {}

mybatis-plus的核心功能
基于baseMapper的CRUD方法
1.insert方法
通过insert来插入一个用户数据,mybatis只提供了这一个方法

2.Delete方法
在Delete中接口提供了四种删除方法
1.根据id删除
2.根据Map进行删除,其中map删除将你传入的对象数值和条件放入map对应的代码书写如图所示
3.根据条件删除,将条件封装到wrapper对象中
4.根据传入的ids数组进行批量的id读取并删除

3.update方法
update方法
updateById方法
其使用方法如下,如果传入的一个实体类参数为空那么就不进行修改,这就是为什么在实体类设计中我们需要将变量变成包装类而不是基本的数据类型
因为包装类当没有进行初始化时,其值为空
但如果某个变量用的是非包装类,其没有初始化时比如int类型id,其默认值是0
那么此时你实例化一个user类进行update方法,就会将所有值设为0


4.select方法
有如下方法
// 根据 ID 查询
T selectById(Serializable id);// 根据 entity 条件,查询一条记录
T selectOne(@Param(Constants.WRAPPER) Wrapper<T> queryWrapper);// 查询(根据ID 批量查询)
List<T> selectBatchIds(@Param(Constants.COLLECTION) Collection<? extends Serializable> idList);// 根据 entity 条件,查询全部记录
List<T> selectList(@Param(Constants.WRAPPER) Wrapper<T> queryWrapper);// 查询(根据 columnMap 条件)
List<T> selectByMap(@Param(Constants.COLUMN_MAP) Map<String, Object> columnMap);// 根据 Wrapper 条件,查询全部记录
List<Map<String, Object>> selectMaps(@Param(Constants.WRAPPER) Wrapper<T> queryWrapper);// 根据 Wrapper 条件,查询全部记录。注意: 只返回第一个字段的值
List<Object> selectObjs(@Param(Constants.WRAPPER) Wrapper<T> queryWrapper);// 根据 entity 条件,查询全部记录(并翻页)
IPage<T> selectPage(IPage<T> page, @Param(Constants.WRAPPER) Wrapper<T> queryWrapper);// 根据 Wrapper 条件,查询全部记录(并翻页)
IPage<Map<String, Object>> selectMapsPage(IPage<T> page, @Param(Constants.WRAPPER) Wrapper<T> queryWrapper);// 根据 Wrapper 条件,查询总记录数
Integer selectCount(@Param(Constants.WRAPPER) Wrapper<T> queryWrapper);
service层的CRUD方法
1.首先在service层中的接口实现IService接口,并将你需要的实体类泛型传入service接口中
接着我们在对应service的实现类中继承ServiceImpl接口并在泛型中传入我们的mapper层和对应的实体类
为什么需要传入mapper层呢?因为在底层我们还是使用的Mapper的接口来进行的数据库操作,并且因为IService中有部分方法没有进行实现,所以我们还需要继承ServiceImpl这个父类,因为这个父类实现了IService接口的一些没有实现的抽象方法


1.插入多条数据
使用saveBatch方法,将传入的一个列表插入到数据库中,使用方法如下

2.更新方法saveOrUpdate()
当传入的类没有id值的时候会视作一个插入的方法
当传入的id存在时就会变成一个更新数据的方法

还有一个是直接根据id进行更新的

3.删除操作

4.查询操作

分页查询
1.添加mybatis-plus插件,能够添加分页查询插件等功能
代码如下,要指定你所使用的数据库

2.代码实现
在Mapper层中mybatisplus提供了一个selectPage方法,可以将对应的page传入
page对象会封装返回的结果,我可以通过page对象获取数据

自定义分页查询
以查询年龄大于1的人举例
1.首先在对应的mapper类中写一个分页查询的方法
要点是返回的数据类型和其中一个参数是Ipage<>其中泛型是你想要查询的实体类

2.在xml文件中将sql语句书写,结尾不能加分号,因为会影响字符串拼接

3.service使用代码如下

其中yaml里面还可以通过type-aliases-pakage指定xml文件中的缩写

条件构造器
在所有的mybatis-plus接口中,所有的方法CRUD方法都存在一个Wrapper这样的条件拼接对象
![]()
使用方法:
QueryWrapper<User> queryWrapper = new QueryWrapper<>();
queryWrapper.eq("name", "John"); // 添加等于条件
queryWrapper.ne("age", 30); // 添加不等于条件
queryWrapper.like("email", "@gmail.com"); // 添加模糊匹配条件
等同于:
delete from user where name = "John" and age != 30and email like "%@gmail.com%"
// 根据 entity 条件,删除记录
int delete(@Param(Constants.WRAPPER) Wrapper<T> wrapper);
继承关系以及各个wrapper类的使用场景

QueryWrapper
组装查询条件
其函数和代表的sql语句写在了下方

其中还能写一个链式调用

组装排序条件:

组装删除条件

组装and和or条件
条件间默认的拼接使用and,如果想使用or就需要使用.or()关键字

指定列查询:
默认是查询所有列,如果没有使用select方法的指定列的话

条件语句示例
使用场景:当我们实际开发中会接收前端传入的参数,我们需要在service层进行一些判断,比如传入的参数是否为空,或者满足什么条件
正常我们使用业务代码会如下所示,需要手写if条件的判断语句,非常麻烦

所以mybatis-plus提供了一个更加方便的方法
可以直接在对应的sql方法中在前面添加一些条件,当满足时才会执行sql语句,不满足时就不会执行

updateWrapper
我们先观察QueryWrapper,他想要修改数据库中的数据的时候需要创建一个实体类,并将实体类传入对应的sql方法中
并且实体类中为空的属性不修改,当你想要将某个数据修改为空时不适合使用QueryWrapper

所以我们使用updateWrapper,它可以将数据修改为空,并且不用创建实体类传入sql方法中
updateWrapper还提供了.set()方法,能够直接将你想要修改的数据进行修改而不用创建实体类

LambdaUpdateWrapper
它存在的作用是通过方法名获取对应的列名
利用Java8的特性,使用匿名函数返回值变量的名称
能够防止自己手写字符串手写错误

核心注解使用:
@TableName
我们在baseMapper泛型中制定了我们要查询的实体类类型,他会根据实体类的名称去查询表名,当实体类和表名称一致时才可以找到

假如实体类名和表名称不一致时就需要@TableName注解指定对应的表名(忽略大小写)

但是假如当多个表名称都不同时,比如都存在一个t_前缀,我们一个一个实体类去添加注解会很麻烦
所有我们有另一种方法
在yaml文件中书写如下配置指定表前缀
mybatis-plus: # mybatis-plus的配置global-config:db-config:table-prefix: sys_ # 表名前缀字符串
@TableId
1.当主键列名和表名不一致时
2.指定主键的策略
使用方法如下
@TableName("sys_user")
public class User {@TableId(value="主键列名",type=主键策略)private Long id;private String name;private Integer age;private String email;
}
type的可选值如下

测试代码如下

在默认没有指定的情况下其id的生成是雪花算法

我们可以通过在yaml文件中指定主键的分配策略,比如下面的代码就是auto
mybatis-plus:configuration:# 配置MyBatis日志log-impl: org.apache.ibatis.logging.stdout.StdOutImplglobal-config:db-config:# 配置MyBatis-Plus操作表的默认前缀table-prefix: t_# 配置MyBatis-Plus的主键策略id-type: auto
注意当我们使用自增长策略时,我们的数据库中的表中也要有自增长这一属性,否则会报错
![]()
TableId关键点总结

雪花算法应用场景
在一个大型的分布式系统中,当数据量非常大时,我们通常会将一个表拆分成多个表
有两种拆分方式:
1.纵向拆分,根据数据的访问频率分为冷热数据进行访问
2.横向拆分,直接将表拆分为多个表进行访问
这些方式都存在一个问题,假设我们采用自增长主键,当自增长到一点限度的时候,会自增长到别的表中
比如有三个表,其id范围分别是1-9, 10-19, 20-29当表1装满时,再次插入一条数据就会变成10,而第二个表中的数据的第一个又是10,所以会出现主键重复的问题,所以雪花算法就是为了解决这种问题而出现

雪花算法是一种简单但有效的生成唯一ID的算法,广泛应用于分布式系统中,如微服务架构、分布式数据库、分布式锁等场景,以满足全局唯一标识的需求。
**你需要记住的: 雪花算法生成的数字,需要使用Long 或者 String类型主键!!**
@TableField
当实体类变量名和数据库列名不一致时使用该注解指定
@TableName("sys_user")
public class User {@TableIdprivate Long id;@TableField("nickname")private String name;private Integer age;private String email;
}


逻辑删除
逻辑删除,可以方便地实现对数据库记录的逻辑删除而不是物理删除。逻辑删除是指通过更改记录的状态或添加标记字段来模拟删除操作,从而保留了删除前的数据,便于后续的数据分析和恢复。
- 物理删除:真实删除,将对应数据从数据库中删除,之后查询不到此条被删除的数据
- 逻辑删除:假删除,将对应数据中代表是否被删除字段的状态修改为“被删除状态”,之后在数据库中仍旧能看到此条数据记录
**逻辑删除实现:**
1. 数据库和实体类添加逻辑删除字段
1. 表添加逻辑删除字段可以是一个布尔类型、整数类型或枚举类型。
```SQL
ALTER TABLE USER ADD deleted INT DEFAULT 0 ; # int 类型 1 逻辑删除 0 未逻辑删除
```
2. 实体类添加逻辑删除属性```SQL
@Data
public class User {// @TableId
private Integer id;
private String name;
private Integer age;
private String email;
@TableLogic
//逻辑删除字段 int mybatis-plus下,默认 逻辑删除值为1 未逻辑删除 1
private Integer deleted;
}```
2. 指定逻辑删除字段和属性值
1. 单一指定```SQL
@Data
public class User {// @TableId
private Integer id;
private String name;
private Integer age;
private String email;
@TableLogic
//逻辑删除字段 int mybatis-plus下,默认 逻辑删除值为1 未逻辑删除 1
private Integer deleted;
}
```
2. 全局指定```YAML
mybatis-plus:
global-config:
db-config:
logic-delete-field: deleted # 全局逻辑删除的实体字段名(since 3.3.0,配置后可以忽略不配置步骤2)
logic-delete-value: 1 # 逻辑已删除值(默认为 1)
logic-not-delete-value: 0 # 逻辑未删除值(默认为 0)
```
3. 演示逻辑删除操作> 逻辑删除以后,没有真正的删除语句,删除改为修改语句!
删除代码:
```Java
//逻辑删除
@Test
public void testQuick5(){
//逻辑删除
userMapper.deleteById(5);
}
```执行效果:
JDBC Connection [com.alibaba.druid.proxy.jdbc.ConnectionProxyImpl@5871a482] will not be managed by Spring
==> Preparing: UPDATE user SET deleted=1 WHERE id=? AND deleted=0
==> Parameters: 5(Integer)
<== Updates: 1
4. 测试查询数据```Java
@Test
public void testQuick6(){
//正常查询.默认查询非逻辑删除数据
userMapper.selectList(null);
}//SELECT id,name,age,email,deleted FROM user WHERE deleted=0
```
并发问题
乐观锁和悲观锁
乐观锁和悲观锁是在并发编程中用于处理并发访问和资源竞争的两种不同的锁机制!!
悲观锁:
悲观锁的基本思想是,在整个数据访问过程中,将共享资源锁定,以确保其他线程或进程不能同时访问和修改该资源。悲观锁的核心思想是"先保护,再修改"。在悲观锁的应用中,线程在访问共享资源之前会获取到锁,并在整个操作过程中保持锁的状态,阻塞其他线程的访问。只有当前线程完成操作后,才会释放锁,让其他线程继续操作资源。这种锁机制可以确保资源独占性和数据的一致性,但是在高并发环境下,悲观锁的效率相对较低。乐观锁:
乐观锁的基本思想是,认为并发冲突的概率较低,因此不需要提前加锁,而是在数据更新阶段进行冲突检测和处理。乐观锁的核心思想是"先修改,后校验"。在乐观锁的应用中,线程在读取共享资源时不会加锁,而是记录特定的版本信息。当线程准备更新资源时,会先检查该资源的版本信息是否与之前读取的版本信息一致,如果一致则执行更新操作,否则说明有其他线程修改了该资源,需要进行相应的冲突处理。乐观锁通过避免加锁操作,提高了系统的并发性能和吞吐量,但是在并发冲突较为频繁的情况下,乐观锁会导致较多的冲突处理和重试操作。
打个比方:以上厕所举例
悲观锁:上厕所时(访问数据),当一个人进去厕所就会锁门,别的人必须要在外面等待你上完然后释放锁才能用你的厕所,上锁和放锁的过程需要时间
乐观锁:上厕所时,我们不给厕所加上锁,当有人想要上厕所时直接开门进去,如果没人则上厕所,如果厕所有人则退出来,然后再开门进行判定是否还有人使用厕所,节省了上锁解锁的时间
在高并发场景下,乐观锁效率会提高特别多
乐观锁实现
1. 乐观锁实现方案和技术:
- 版本号/时间戳:为数据添加一个版本号或时间戳字段,每次更新数据时,比较当前版本号或时间戳与期望值是否一致,若一致则更新成功,否则表示数据已被修改,需要进行冲突处理。
- CAS(Compare-and-Swap):使用原子操作比较当前值与旧值是否一致,若一致则进行更新操作,否则重新尝试。
- 无锁数据结构:采用无锁数据结构,如无锁队列、无锁哈希表等,通过使用原子操作实现并发安全。
版本号的意思是,假设有ab两个进程取了一个数据,每个取出来的数据都携带一个版本号(时间截)
此时ab两个进程版本号都是1,当a对数据进行修改后对版本号进行了更新,此时版本号是2,然后当b进程修改完数据后一比对发现版本号对不上了,此时就会重新拿取数据进行修改
即每次修改都会检查版本号是否是最新的版本号

代码实现
我们首先将乐观锁的插件放在启动器类里面,以让他添加到ioc容器中
代码如下

然后再数据库中添加对应的字段
ALTER TABLE USER ADD VERSION INT DEFAULT 1 ; # int 类型 乐观锁字段
再实体类中加入一个@Version注解表明这个变量是一个版本号就可以了
@Version
private Integer version;
代码实现
//演示乐观锁生效场景
@Test
public void testQuick7(){//步骤1: 先查询,在更新 获取version数据//同时查询两条,但是version唯一,最后更新的失败User user = userMapper.selectById(5);User user1 = userMapper.selectById(5);user.setAge(20);user1.setAge(30);userMapper.updateById(user);//乐观锁生效,失败!userMapper.updateById(user1);
}
防全表更新和删除
防止删库跑路(滑稽)
添加对应的mybatis-plus插件,同样在启动类中添加
@Bean
public MybatisPlusInterceptor mybatisPlusInterceptor() {MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();interceptor.addInnerInterceptor(new BlockAttackInnerInterceptor());return interceptor;
}
}
示例如下所示

相关文章:
ssm-mybatisPlus学习笔记
注意!mybatisPlus只能够进行单表操作,其他的仍需要mybatis 1.快速入门 编写启动类 MapperScan("com.atguigu.mapper") SpringBootApplication public class MainApplication {public static void main(String[] args) {SpringApplication.r…...
【算法学习笔记】35:扩展欧几里得算法求解线性同余方程
线性同余方程问题 线程同余方程问题是指 a x ≡ b ( m o d m ) ax \equiv b~(mod~m) ax≡b (mod m),给定 a a a、 b b b和 m m m,找到一个整数 x x x使得该方程成立,即使得 a x m o d m b ax~mod~mb ax mod mb,随便返回任何一个…...
线性规划:机器学习中的优化利器
一、线性规划的基本概念 线性规划(Linear Programming, LP)是运筹学中数学规划的一个重要分支,用于在一组线性不等式的约束条件下,找到线性目标函数的最大值或最小值。其问题可以表述为: 在一组线性约束条件 s.t.&am…...
Ubuntu开发中的问题
1.退出anaconda指令:conda deactivate 2.Linux系列:一打开终端就默认进入conda的base环境,取消方法 在终端输入conda config --show,会显示所有的配置信息,然后利用conda config --set来修改此配置: conda config --se…...
MAC 地址转换为标准大写格式
// ConvertToStandardMac 将 MAC 地址转换为标准格式,确保每个字节都是两位,并且字母是大写的 func ConvertToStandardMac(mac string) (string, error) { // 分割 MAC 地址的每一部分 parts : strings.Split(mac, ":") // 确保每部分是两…...
使用插件SlideVerify实现滑块验证
作者gitee地址:https://gitee.com/monoplasty/vue-monoplasty-slide-verify 使用步骤: 1、安装插件 npm install --save vue-monoplasty-slide-verify 2、在main.js中进行配置 import SlideVerify from vue-monoplasty-slide-verify; Vue.use(SlideV…...
深入探索 Nginx 的高级用法:解锁 Web 服务器的强大潜能
在当下互联网技术飞速发展的浪潮中,Nginx 凭借其轻量级、高性能的特性,在 Web 服务器和反向代理服务器领域脱颖而出,成为众多开发者和运维工程师的得力工具。它不仅能高效处理静态资源,在负载均衡、反向代理等方面也表现出色。然而…...
(01)搭建开发环境
1.安装虚拟机软件 VMware Workstation Pro 17 2.虚拟机安装ubuntu20.4系统 3.安装VMtools工具 4.安装vim编辑器 sudo apt install vim 4.安装SSH服务 选择下载源为:http://mirrors.aliyun.com/ubuntu在线安装:sudo apt-get install openssh-serv…...
Win11桌面右键刷新选项在二级界面的修正方法
win10已经被弃用了,现在的win11在桌面右键时,“刷新”按钮在二级界面。除此以外,在资源管理器中浏览文件的时候,很多其他选项也都被放在了二级界面,非常不方便。接下来介绍一个把右键菜单栏中的所有选项都显示在一级界…...
配电室防静电地板通常用哪种
配电室是指带有低压负荷的室内配电场所,包含变压器、配电柜、开关设备等,主要为低压用户配送电能。为防止设备故障、避免火灾爆炸、保护人员安全等均会安装防静电地板。那么配电室防静电地板通常用哪种? 一、全钢防静电地板 1. 全钢三聚氰胺…...
【重庆市乡镇界】面图层shp格式arcgis数据乡镇名称和编码wgs84坐标无偏移内容测评
标题中的“最新重庆市乡镇界面图层shp格式arcgis数据乡镇名称和编码wgs84坐标无偏移最新”指的是一个地理信息系统(GIS)的数据集,特别设计用于ArcGIS软件。这个数据集包含了重庆市所有乡镇的边界信息,以Shapefile(.shp…...
68,[8] BUUCTF WEB [RoarCTF 2019]Simple Upload(未写完)
<?php // 声明命名空间,遵循 PSR-4 自动加载规范,命名空间为 Home\Controller namespace Home\Controller;// 导入 Think\Controller 类,以便扩展该类 use Think\Controller;// 定义 IndexController 类,继承自 Think\Control…...
Windows电脑桌面记录日程安排的提醒软件
在快节奏的现代生活中,工作效率成为了衡量个人能力的重要标准之一。然而,日常办公中常常会遇到各种琐事和任务,如果没有合理安排日程,很容易陷入混乱,导致效率低下。因此,做好日程安排对于日常工作至关重要…...
TiDB与Oracle:数据库之争,谁能更胜一筹?
TiDB与Oracle:数据库之争,谁能更胜一筹? 最近有很多朋友在讨论数据库的选择问题,尤其是在面对大数据、分布式系统时。作为两款在企业级数据库中非常受欢迎的产品,TiDB和Oracle常常被拿来对比。TiDB 是一款开源分布式数…...
USART_串口通讯中断案例(HAL库实现)
引言 本次,继续对前面寄存器实现的串口通讯中断案例使用HAL库进行二次实现,因此这里会省略一些重复内容,如果大家不清楚的话请参考下面链接:USART_串口通讯中断案例(一)(寄存器实现)…...
【MySQL】存储引擎有哪些?区别是什么?
频率难度60%⭐⭐⭐⭐ 这个问题其实难度并不是很大,只是涉及到的相关知识比较繁杂,比如事务、锁机制等等,都和存储引擎有关系。有时还会根据场景选择不同的存储引擎。 下面笔者将会根据几个部分尽可能地讲清楚 MySQL 中的存储引擎࿰…...
[OpenGL]实现屏幕空间环境光遮蔽(Screen-Space Ambient Occlusion, SSAO)
一、简介 本文介绍了 屏幕空间环境光遮蔽(Screen-Space Ambient Occlusion, SSAO) 的基本概念,实现流程和简单的代码实现。实现 SSAO 时使用到了 OpenGL 中的延迟着色 (Deferred shading)技术。 按照本文代码实现后,可以实现以下…...
linux-NFS网络共享存储服务配置
1.NFS服务原理 NFS会经常用到,用于在网络上共享存储,这样讲,你对NFS可能不太了解,举一个例子, 加入有三台机器A,B,C,它们需要访问同一个目录,目录中都是图片,传统的做法是把这些 图…...
w-form-select.vue(自定义下拉框组件)
文章目录 1、w-form-select.vue 组件中每个属性的含义2、实例3、源代码 1、w-form-select.vue 组件中每个属性的含义 好的,我们来详细解释 w-form-select.vue 组件中每个属性的含义,并用表格列出它们是否与后端字段直接相关: 属性解释表格&…...
ovs实现lb负载均衡
负载均衡定义 负载均衡器的实现原理是通过硬件或软件设备将客户端访问流量根据转发策略分发到多个服务器或设备上,以确保系统的负载均衡。常见的实现方式包括: 二层负载均衡:使用虚拟MAC地址方式,根据OSI模型的二层进行负载均…...
铭豹扩展坞 USB转网口 突然无法识别解决方法
当 USB 转网口扩展坞在一台笔记本上无法识别,但在其他电脑上正常工作时,问题通常出在笔记本自身或其与扩展坞的兼容性上。以下是系统化的定位思路和排查步骤,帮助你快速找到故障原因: 背景: 一个M-pard(铭豹)扩展坞的网卡突然无法识别了,扩展出来的三个USB接口正常。…...
测试微信模版消息推送
进入“开发接口管理”--“公众平台测试账号”,无需申请公众账号、可在测试账号中体验并测试微信公众平台所有高级接口。 获取access_token: 自定义模版消息: 关注测试号:扫二维码关注测试号。 发送模版消息: import requests da…...
Android Wi-Fi 连接失败日志分析
1. Android wifi 关键日志总结 (1) Wi-Fi 断开 (CTRL-EVENT-DISCONNECTED reason3) 日志相关部分: 06-05 10:48:40.987 943 943 I wpa_supplicant: wlan0: CTRL-EVENT-DISCONNECTED bssid44:9b:c1:57:a8:90 reason3 locally_generated1解析: CTR…...
【力扣数据库知识手册笔记】索引
索引 索引的优缺点 优点1. 通过创建唯一性索引,可以保证数据库表中每一行数据的唯一性。2. 可以加快数据的检索速度(创建索引的主要原因)。3. 可以加速表和表之间的连接,实现数据的参考完整性。4. 可以在查询过程中,…...
3.3.1_1 检错编码(奇偶校验码)
从这节课开始,我们会探讨数据链路层的差错控制功能,差错控制功能的主要目标是要发现并且解决一个帧内部的位错误,我们需要使用特殊的编码技术去发现帧内部的位错误,当我们发现位错误之后,通常来说有两种解决方案。第一…...
连锁超市冷库节能解决方案:如何实现超市降本增效
在连锁超市冷库运营中,高能耗、设备损耗快、人工管理低效等问题长期困扰企业。御控冷库节能解决方案通过智能控制化霜、按需化霜、实时监控、故障诊断、自动预警、远程控制开关六大核心技术,实现年省电费15%-60%,且不改动原有装备、安装快捷、…...
定时器任务——若依源码分析
分析util包下面的工具类schedule utils: ScheduleUtils 是若依中用于与 Quartz 框架交互的工具类,封装了定时任务的 创建、更新、暂停、删除等核心逻辑。 createScheduleJob createScheduleJob 用于将任务注册到 Quartz,先构建任务的 JobD…...
使用Spring AI和MCP协议构建图片搜索服务
目录 使用Spring AI和MCP协议构建图片搜索服务 引言 技术栈概览 项目架构设计 架构图 服务端开发 1. 创建Spring Boot项目 2. 实现图片搜索工具 3. 配置传输模式 Stdio模式(本地调用) SSE模式(远程调用) 4. 注册工具提…...
Bean 作用域有哪些?如何答出技术深度?
导语: Spring 面试绕不开 Bean 的作用域问题,这是面试官考察候选人对 Spring 框架理解深度的常见方式。本文将围绕“Spring 中的 Bean 作用域”展开,结合典型面试题及实战场景,帮你厘清重点,打破模板式回答,…...
Linux部署私有文件管理系统MinIO
最近需要用到一个文件管理服务,但是又不想花钱,所以就想着自己搭建一个,刚好我们用的一个开源框架已经集成了MinIO,所以就选了这个 我这边对文件服务性能要求不是太高,单机版就可以 安装非常简单,几个命令就…...
