微服务全套

微服务导学

服务拆分

如何把单一的大项目如何拆分成一个个小项目

远程调用

每个小的单体项目,在物理上是隔绝开的,使用的是不同的Tomcat,有独立的运维和部署,互相之间如何调用就涉及到了远程调用的知识

学习微服务的最好方法是尝试着把一个大项目分成一个个小问题,然后解决这个过程中出现的问题

MybatisPlus

介绍

快速入门

对于单表查询很好用

常用注解

MyBatisPlus用过扫描Mapper继承的实体类,基于反射获取实体类的信息作为数据库信息(也就是对应数据库的字段名)从而编写单表查询语句

实体类的字段名转数据库的字段名有约定如下,这就要求我们在编写实体类,以及数据库的时候要规范

一定要注意的是,一定要有主键,有成员变量为id的或者用@TableId这个注解把主键是什么标出来

@TableId有两个属性,value是给这个成员变量起别名,并设置为主键,type是给这个成员变量设置如下属性

常用配置

默认id的type属性为雪花算法生成,但是优先级不如注解的高

java 复制代码
mybatis-plus:
  mapper-locations: '[classpath*:/mapper/**/*.xml]'
  type-aliases-package: com.itheima.map.domain.po
  global-config:
    db-config:
      id-type: assign-id
      update-strategy: not-null
  configuration:
    map-underscore-to-camel-case: true
    cache-enabled: false

这些配置几乎都是默认的,不用自己配置

需要的时候看文档就行

条件构造器

在给出复杂的where条件的时候可以使用条件构造器构造出来的一个类传入参数

java 复制代码
    @Test
    void testQuerywrapper() {
        //在查询中 Wrapper用来填充复杂的条件语句,同时可以对查询结果做筛选
        QueryWrapper<User> queryWrapper = new QueryWrapper<User>()
                .select("id","username","phone","balance")
                .like("username","o")
                .ge("balance",1000);
        List<User> users = userMapper.selectList(queryWrapper);
        users.forEach(System.out::println);

        //在更新中 Wrapper设置条件语句,还需要一个实体类来传递参数
        User user = new User();
        user.setBalance(10000);
        QueryWrapper<User> queryWrapper1 = new QueryWrapper<User>()
                .eq("username","Lucy");
        userMapper.update(user,queryWrapper1);

        //在执行比较特殊的update语句的时候,可以手写sql语句
        User user1 = new User();
        user1.setUsername("zhangsan");
        UpdateWrapper<User> updateWrapper = new UpdateWrapper<User>()
                .setSql("balance=balance-1000")
                .eq("username","mary");
        userMapper.update(user,updateWrapper);

    }

在构建wrapper的时候直接传入字段名是属于硬编码,要尽量避免,可以通过如下方法,传入函数的get方法来避免

自定义sql

IService接口

基本用法

自定义接口继承IService接口

自定义实现类继承IService的实现类

要传递baseMapper给ServiceImpl(IService的实现类)是因为调用Mapper方法时要知道要调用哪一个类的Mapper

开发基础业务接口

java 复制代码
@RestController
@RequestMapping("/users")
@Api(tags="用户管理相关接口")
public class UserController {
    private final UserService userService;

    public UserController(UserService userService) {
        this.userService = userService;
    }

    @PostMapping
    @ApiOperation("新增用户")
    public void saveUser(@RequestBody UserFormDTO userFormDTO) {
        //把DTO拷贝到pojo
        User user = BeanUtil.copyProperties(userFormDTO,User.class);
        userService.save(user);
    }
    @DeleteMapping("/{id}")
    @ApiOperation("删除员工")
    public void deleteUser(@PathVariable String id) {
        //删除用remove
        userService.removeById(id);
    }
    @GetMapping("/{id}")
    @ApiOperation("根据id查询用户")
    public UserVO getUserById(@PathVariable String id) {
        User user = userService.getById(id);
        return BeanUtil.copyProperties(user,UserVO.class);
    }
    @GetMapping
    @ApiOperation("根据id批量删除")
    public List<UserVO> getUserByIds(@RequestParam List<Long> ids) {
        //批量查询用list
        List<User> userList = userService.listByIds(ids);
        //因为返回类型是固定的,所以类的复制,转换会很常用
        return BeanUtil.copyToList(userList,UserVO.class);
        
    }

开发复杂业务接口

baseMapper是编译时多态,userMapper是运行时多态,通过泛型绑定实现了,自定义实现类继承mp提供的serviceImpl<UserMapper,User>的时候通过泛型绑定了,所以这里的BaseMapper实际上运行时使用的是userMapper对象,尽管deductMoneyById是不在BaseMapper中自定义的方法。

Lambda方法

在查询参数比较多的时候,不建议用requestParam一个一个查询,太过于麻烦,可以定义一个对象来接收

ISerice的批量新增

每一次循环只插入一条数据,一共要插入十万条数据就进入十万次数据库,每一次进入数据库就是一次网络请求,网络请求比较耗时间,所以效率比较低

每一次循环插入一千条数据,要插入十万条数据就要进入一百次数据库,执行网络请求的次数变少了,效率提升了,但是由于还是一条sql执行一次新增用户,效率还没有达到最好

一次性插入十万条数据,只进入一次数据库,且一条sql执行批量新增用户,一条sql可以添加多个用户,效率最高

java 复制代码
spring:
  datasource:
    url: jdbc:mysql://127.0.0.1:3306/mp?useUnicode=true&characterEncoding=UTF-8&autoReconnect=true&serverTimezone=Asia/Shanghai&rewriteBatchedStatements=true
    driver-class-name: com.mysql.cj.jdbc.Driver
    username: root
    password: 1234
java 复制代码
@SpringBootTest
class MpDemoApplicationTests {
    @Autowired
    private UserService userService;

    private User buildUser(int i) {
        User user = new User();
        user.setUsername("user_" + i);
        user.setPassword("123");
        user.setPhone("" + (18688190000L + i));
        user.setBalance(2000);
        user.setInfo("{\"age\": 24, \"intro\": \"英文老师\", \"gender\": \"female\"}");
        user.setCreateTime(LocalDateTime.now());
        user.setUpdateTime(user.getCreateTime());
        return user;
    }
    @Test
    void testSaveBatch() {
        // 准备10万条数据
        List<User> list = new ArrayList<>(1000);
        long b = System.currentTimeMillis();
        for (int i = 1; i <= 100000; i++) {
            list.add(buildUser(i));
            // 每1000条批量插入一次
            if (i % 1000 == 0) {
                userService.saveBatch(list);
                list.clear();
            }
        }
        long e = System.currentTimeMillis();
        System.out.println("耗时:" + (e - b));
    }

代码生成器

插件功能

Docker

快速入门

-部署MySQL

应用的运行对环境和操作系统有强要求,windows64位的qq换到windows32位上面就不能运行

命令解读

docker run是创建并运行一个容器,但可能会中途停止,-d是让容器一直运行

--name是给容器指定一个名字,以后去操作容器的时候就是根据名字来的,这个名字是这里我们自己起的名字

-p 3306:3306前一个端口号是虚拟机自己的端口号,后面那个端口号是虚拟机内部给mysql容器分配的端口号,不同的容器前面的3306虚拟机端口号是不变的,后面的端口号会不同,因为虚拟机内部是隔离的,外部不能直接访问到内部的容器,只能通过虚拟机提供的端口号来访问虚拟机然后再访问容器

-e 是设置环境变量

  • TZ=Asia/Shanghai:设置容器时区为上海,避免 MySQL 时间与宿主机不一致。
  • MYSQL_ROOT_PASSWORD=123强制必填,用于初始化 MySQL 的 root 用户密码,是 MySQL 镜像的核心启动参数,无此参数容器会启动失败。

最后的mysql

指定运行的镜像名称,docker daemon 基于该镜像创建容器实例;本地无镜像时自动从镜像仓库拉取

以后操作容器时,--name指定要操作的容器,docker daemon找到对应容器之后会自己起个名字自己用

常见命令

docker pull

去镜像仓库里面拉取镜像要用pull,可能会有必须输入的内容,这部分可以去docker hub网站上面去搜索要拉取的镜像名称来确认

docker image

镜像的英文翻译是image,要查看镜像使用这个命令就行

docker save -o nginx.tar nginx:latest

将镜像下载到本地镜像列表要用save命令,具体内容如下docker save -o nginx.tar nginx:latest意思是将nginx镜像的最新版本下载到本地的文件nginx.tar里面

docker load -i nginx

去本地镜像列表里可以下载镜像用load命令

忘了都可以用--help查看

容器操作

命令 作用 示例 (Nginx)
docker run -d --name nginx -p 8081:80 nginx 启动并运行 Nginx 容器(推荐) docker run -d --name nginx -p 8081:80 nginx
docker ps 查看正在运行的容器 docker ps
docker ps --all 查看所有容器(包括停止的) docker ps -a
docker start nginx 启动已存在的 Nginx 容器 docker start nginx
docker stop nginx 安全停止 Nginx 容器 docker stop nginx
docker restart nginx 重启 Nginx 容器 docker restart nginx
docker rm -f nginx 强制删除 Nginx 容器(解决端口冲突用) docker rm -f nginx
软件 端口 启动命令
Nginx 8081 8081:80
phpMyAdmin 8080 8080:80
MySQL 3306 3306:3036
命令 作用 示例 (Nginx)
docker exec -it nginx /bin/bash 进入 Nginx 容器终端 docker exec -it nginx bash
exit 退出容器,回到宿主机 exit
命令 作用 示例 (Nginx)
docker logs nginx 查看 Nginx 日志 docker logs nginx
docker logs -f nginx 实时跟踪 Nginx 日志 docker logs -f nginx

数据卷

镜像就是最小化的系统,只给你准备必要的,最少的,运行所必需的,所以在容器内修改容器是非常困难的

在创建数据卷的时候,每创建一个数据卷就会对应宿主机文件系统里的一个文件

每一个数据卷里的都和宿主机里的文件有对应关系

在修改宿主机文件系统里面的文件时容器内的文件也会改变

Docker 挂载数据卷时

把宿主机的某个目录,直接映射进容器的文件系统树。

  • 宿主机写 → 直接写硬盘

  • 容器读 → 直接读硬盘

  • 两边看到的是同一块物理存储空间

没有同步、没有传输、没有复制。改一个 = 改另一个。


为什么会这样?

因为容器本质不是虚拟机,容器是共享宿主机内核的进程。

它没有自己独立的硬盘,只能通过挂载方式,使用宿主机的真实文件。


最终一句话总结

宿主机和容器修改的是硬盘上同一份真实文件,所以一边改,另一边立刻变。

相关推荐
亚历克斯神2 小时前
JVM 内存管理 2026:深度解析与调优实战
java·spring·微服务
逻辑驱动的ken3 小时前
Java高频面试题:03
java·开发语言·面试·求职招聘·春招
广师大-Wzx3 小时前
一篇文章看懂MySQL数据库(下)
java·开发语言·数据结构·数据库·windows·python·mysql
野生技术架构师3 小时前
Java NIO到底是个什么东西?
java·开发语言·nio
likerhood4 小时前
简单工厂设计模式
java·ide·intellij-idea
派大星酷5 小时前
Java 调用 Kimi API 实战:实现与大模型的简单对话
java·开发语言·ai编程
猫耳球团6 小时前
IDEA与Cursor跨平台协作指南
java·ide·intellij-idea
亚历克斯神6 小时前
Java 职业发展:2026 指南
java·spring·微服务
xuhaoyu_cpp_java7 小时前
Maven学习(二)
java·经验分享·笔记·学习·maven