Docker 快速入门实操教程ER(完结)

Docker 快速入门实操教程(完结)

如果安装好Docker不知道怎么使用,不理解各个名词的概念,不太了解各个功能的用途,这篇文章应该会对你有帮助。

前置条件:已经安装Docker并且Docker成功启动。

实操内容:使用Docker容器替换本地安装的程序并迁移数据(MySQL、redis)。

最终目的:熟练使用Docker各项功能。

理解概念

Docker官方提供了一个分发平台DockerHub,可以从上面拉取已经提供好的镜像直接构建容器运行。

这个过程会涉及到Docker的一些概念,在刚接触的时候比较抽象,这里以烘焙出一个蛋糕为例子说明一下:

  • Dockerfile: 蛋糕的配方。配方上详细列出了需要的材料(如面粉、糖、鸡蛋)以及烘焙的步骤(如先将面粉和糖混合,然后加入鸡蛋搅拌)。
  • 镜像(Image): 按照配方做出了一个半成品蛋糕,这就是蛋糕的"镜像" 。这个蛋糕可以被任何人复制,每一个复制品都会和原蛋糕一模一样。
  • 容器(Container): 将半成品蛋糕烘焙后,得到一个可食用的蛋糕。可以根据同一个镜像制作出很多个完全一样的蛋糕,也可以在烘焙时自己加一些材料。每个蛋糕都是独立的,和其他蛋糕没有关联。

所以从DockerHub拉取镜像并且跑起来的过程就可以理解为:

  1. 镜像提供者编写好了配方( Dockerfile ),将其制成( 构建 )了半成品蛋糕( 镜像 )。
  2. 用户购买( 拉取 )这个半成品蛋糕。
  3. 烘焙( 创建 )后得到了一个可食用的蛋糕( 容器 ),食用蛋糕( 运行容器 )。
  4. 通常创建容器和运行容器都会归拢在同一步:创建并运行。

还有另外两个比较重要的概念: 层(Layers)缓存(Cache) ,目前不会接触到,可以在看 构建/推送镜像 这一节时再去深入理解。

创建/运行容器

每一步都提供了Docker desktop(简称桌面版)的操作截图和终端命令(桌面版界面友好但局限较大,仅适合初步上手)。

拉取镜像

从DockerHub拉取MySQL镜像到本地,这一步可能会因为网络原因失败,可以配置其他镜像源或者使用代理,网上教程很多。

image-20240128210738711

终端命令

 

bash

复制代码

docker pull 仓库地址/命名空间/镜像名称:标签

  • 仓库地址: 没有显式指定仓库地址时,默认会从DockerHub查找镜像;拉取私有仓库的镜像,需要指定仓库地址。
  • 命名空间: 截图最后有一个名为 ubuntu/mysql 的镜像,其中 ubuntu 是命名空间,用以区分不同的个人或组织发布的镜像。没有显式指定命名空间时,默认会查找官方团队发布的镜像。
  • 镜像名称: 需要拉取的镜像的名称。
  • 标签: 没有显式指定标签时,默认会拉取 latest 标签, latest 表示这是最新的版本。

通过 docker pull 拉取镜像并不是必须的,在 docker run 时,如果本地不存在指定镜像,Docker会自动拉取。

创建并运行容器

拉取完成后,通过 docker run 创建容器并运行前进行一些配置:

image-20240128213738553

终端命令

 

bash

复制代码

# 截图对应命令 docker run -d --name mysql_8.3.0 -p 3306:3306 -e MYSQL_ROOT_PASSWORD=root mysql:latest # 完整命令 docker run [选项参数] 仓库地址/命名空间/镜像名称:标签 [命令行] [命令行参数]

  • 选项参数:

    --name :设置容器名称,不能重复,这里使用的是 镜像名_版本号 的方式。

    -p :设置端口映射,将宿主机的 3306 端口映射到容器的 3306 端口,宿主机上的其他进程通过该端口才能访问到容器内的服务。如果不配置端口映射,则只能在容器内部访问服务或通过虚拟网络让容器可以相互通信。

    -e :设置环境变量,配置 MYSQL_ROOT_PASSWORD=root 用以指定root用户密码,这是由镜像创建者约定的,不同的镜像配置项会有所不同。

    -v :设置目录挂载,用法参考 目录挂载 章节。

    -d :让容器在后台运行

  • 命令行: 在容器启动时执行命令(如 ls ),可以省略。

  • 命令行参数: 传给 命令行 的额外参数(如 /etc ,这样在容器启动时就会执行 ls /etc ),可以省略。

常用命令

容器已经创建好后就不再适用于 docker run 命令了, docker run 命令主要是用于创建新的容器并运行,如果需要启动已经存在的容器,则使用 docker start 命令。

 

bash

复制代码

# 列出所有容器 docker ps -a # 列出所有镜像 docker image ls docker images # 启动容器 docker start 容器名称/容器ID # 停止容器 docker stop 容器名称/容器ID # 强制停止容器 docker kill 容器名称/容器ID # 重启容器 docker restart 容器名称/容器ID # 删除容器 docker rm 容器名称/容器ID # 删除镜像 docker rmi 容器名称/容器ID

目录挂载

现存问题:

  • 数据没有保存到宿主机中,当容器删除后,数据就丢失了。
  • 宿主机和容器之间的文件传递比较麻烦。
  • 多个容器需要共享数据。

目录挂载可以解决以上问题,Docker为目录挂载提供了三种方式:

  • bind mount: 把宿主机目录映射到容器内,双向文件传递。适合变动比较频繁的场景,比如代码目录、配置文件等。

  • volume: 由容器创建和管理,存储在宿主机中,官方推荐,Linux 文件系统。适合存储不需要关心的数据,如数据库数据。

  • tmpfs mount: 适合存储临时文件,存储在宿主机内存中。不可多容器共享。

以MySQL镜像为例,其 Dockerfile 中写了创建 volume 用于持久化保存数据的命令(其他镜像也可以通过这种方式查看需要持久化的目录)。

image-20240128224015528

虽然 Dockerfile 中有创建 volume 的命令,但是如果创建容器时没有主动为 volume 命名,其就是匿名 volume ,Docker会为匿名 volume 随机生成一个名称,当挂载该 volume 的容器被删除后,该 volume 也会被删除。

当创建容器时主动指定的 volume 路径和 Dockerfile 约定的路径一致,则该镜像创建的 volume 就不会被挂载为匿名 volume 了,容器删除后该 volume 也会保留,这也是最方便的一种命名方式。

image-20240128220629652

终端命令

 

bash

复制代码

docker run -d --name mysql_8.3.0 -p 3306:3306 -e MYSQL_ROOT_PASSWORD=root -v=mysql_volume:/var/lib/mysql -v D:\mount:/pc_mount mysql:latest

挂载目录时,如果只赋予了名称则是 volume 方式,如果指定了具体目录就是 bind mount 方式。

所以在这个容器中:

  1. 将容器内的 /var/lib/mysql 目录挂载为 volume 并且命名为 mysql_volume
  2. 将宿主机的 D:\mount目录映射至容器中的 /pc_mount

在挂载目录时,如果你指定的目录不存在于容器中,则会自动创建,这里的 /pc_mount 目录就会自动被创建。

迁移实操

现在需要将宿主机中MySQL数据迁移到容器中,打算采用navicat的数据迁移工具,那么就需要同时运行两个数据库,端口同为 3306 会冲突,宿主机上MySQL端口改起来并不方便,容器创建后端口也不能修改,那么就可以使用数据挂载的方式。

迁移方案:

  1. 停止运行端口为 3306 的MySQL容器。
  2. 新创建一个MySQL容器,端口指定为 3305 (或其他任意未被占用的端口),指定 volume 的名称和端口 3306 的容器一致。
  3. 迁移数据,删除端口为 3305 的容器,运行端口为 3306 的容器,数据迁移成功。

当数据库文件较大时,使用navicat迁移则会显得有些性能不足了,这时候就需要通过命令行导入:

  1. 将需要导入的SQL文件放在宿主机挂载的目录下(宿主机: D:\mount ;容器: /pc_mount )。

  2. 打开容器的终端

     bash 

    复制代码

    docker exec -it mysql_8.3.0 bash
  3. 登入MySQL并选择需要导入的数据库

     bash 

    复制代码

    mysql -u root -proot use test-base; source /pc_mount/001.sql;

从容器中导出SQL文件到宿主机同理,将SQL文件导出至挂载的 /pc_mount 目录下,在宿主机的 D:\mount 就可以看到。

虚拟网络

每个Docker容器都运行在自己的环境中,互不干扰,所以上述内容中都依赖宿主机的端口映射进行容器通信。但是有些时候我们只要让这个项目能在宿主机上访问到,并不在意其所依赖的服务是否能够被宿主机操作和管理。就可以通过Docker提供的虚拟网络实现容器之间的通信,再映射项目入口到宿主机即可。

桌面版并没有为虚拟网络提供较好的GUI支持,需要终端执行。

 

bash

复制代码

# 查看已存在的虚拟网络 docker network ls

默认已经存在了三个虚拟网络,这是由Docker创建的,对应着不同的网络驱动类型,驱动类型的区别如下:

  • Bridge网络: 默认值。容器在独立的网络空间运行,可以相互通信并访问外部网络。容器内服务能通过端口映射被外部访问。
  • Host网络: 容器共享宿主机的网络空间,不再需要端口映射,直接使用宿主机的端口。这种模式提供了最高的网络性能,但是失去了隔离性。
  • None网络: 容器拥有自己的网络空间,但不配置任何网络接口。它只有本地回环接口,没有任何外部网络访问能力,提供了最高的网络隔离性。
 

bash

复制代码

# 创建名为 test_net 的网络 docker network create test_net # 在该网络下创建两个容器 docker run --name redis_temp --network=test_net -d redis:latest docker run --name redisinsight -p 8001:8001 --network test_net -d redislabs/redisinsight:latest

创建了redis容器,但是并没有为其映射端口。所以现在在宿主机中并不能访问到这个redis容器。

创建了redisInsight容器并且映射了8001端口,这是一个redis的GUI工具,用于测试是否可以通过虚拟网络访问到redis容器。

访问 http://localhost:8001/ 进入redisInsight的主页,添加一个redis数据库。

Docker内部的DNS服务会自动将容器名称解析为容器对应的IP地址(即容器名称就是域名),所以主机地址填写容器名称即可。

image-20240129172212539

连接成功,这样既可以操作容器内的redis数据,又不会占用宿主机自身的redis应用抢占端口。同理,部署其他项目时,如果项目容器需要连接数据库容器,也可以通过虚拟网络实现。

如果容器已经被创建,可以更改已存在的容器的连接的网络

 

bash

复制代码

docker network connect 网络名称 容器名称

使用技巧

查看软件版本

部分镜像的 Taglatest ,并没有明确指出具体的版本号,想要查看版本号就只能手动查看。

桌面版点击容器右侧 ··· 打开更多选项,选择 Open in terminal 进入容器的终端,执行该软件查看版本的命令。

终端命令

 

bash

复制代码

docker exec mysql_8.3.0 mysql -V

但是问题就来了,如果需要版本号是为了给容器命名,这种方案需要先运行容器,将容器删除,再重新创建容器,很麻烦。

通常镜像的环境变量中会指明版本号,可以直接点开镜像查看

image-20240128220336815

终端命令

 

bash

复制代码

docker inspect mysql:latest

这个方式虽然比较方便,但是需要进行推测,并非一定正确。

保持容器运行

当在桌面版运行ubuntu等容器时,会发现容器启动后就停止了,进入 Exited 状态,如果想要容器持续运行,就需要需要在容器内部执行一个持续运行的进程。

桌面版已经不能满足需求了,需要终端执行

 

bash

复制代码

docker run -it --name ubuntu_22.04 ubuntu:latest

-t 指令分配一个虚拟的终端或控制台,可以让容器持续运行不会关闭。

-i 指令可以让打开的控制台能够接受用户输入。

构建/推送镜像

想要通过Docker将项目部署到服务器上或是分发项目供他人使用,就需要将项目构建为镜像,官方主要推荐通过 Dockerfile 构建镜像。 Dockerfile 是一个文本文件(无文件后缀),由一系列的命令和参数构成,这些命令对应了在构建镜像时的操作步骤。

编写Dockerfile文件

Dockerfile常用指令:

  • FROM: 指定基础镜像。所有后续的操作都是基于这个基础镜像进行的。
  • WORKDIR: 设定后续命令的执行目录。
  • COPY: 复制文件、指定目录中的所有内容(不含目录本身)到镜像中。
  • ADD: 复制文件、指定目录中的所有内容(不含目录本身)到镜像中。对tar格式的压缩文件会自动解压。
  • RUN: 构建过程中执行命令。比如安装一些软件,创建一些文件等。
  • CMD: 为容器提供默认的执行命令,会被 docker run 的命令行参数覆盖。
  • ENTRYPOINT: 为容器提供默认的执行命令,不会被 docker run 的命令行参数覆盖。
  • EXPOSE: 公开容器的一个端口供外部访问。

通过maven执行 package 手动将项目打包,命名为 output-dem.jar ,在项目根目录下新建一个 Dockerfile 文件:

 

dockerfile

复制代码

# 使用JDK17基础镜像 FROM openjdk:17-jdk-slim # 设置工作目录,容器也会使用该目录作为工作目录 WORKDIR /app # 将jar包复制到/app路径下 COPY target/output-demo.jar app.jar # 设置在运行此镜像后默认执行的命令,让它运行刚才的jar包 ENTRYPOINT ["java", "-jar", "app.jar"] # 暴露端口,取决于项目实际使用的端口号 EXPOSE 8080

如果不是Java开发,设备上并没有安装 JDKmaven 等构建需要的环境(其他语言同理),但是又有打包项目的需求,则可以通过多阶段构建的方式,在镜像中完成编译等操作:

 

dockerfile

复制代码

# 使用包含JDK17和Maven3.8.5的基础镜像 # 将本构建阶段命名为 build ,以便在后面的阶段中引用 FROM maven:3.8.5-openjdk-17-slim AS build # 设置工作目录,容器也会使用该目录作为工作目录 WORKDIR /app # 将当前目录下的所有文件添加到工作目录下(.和./都可以表示当前目录) ADD . . # 使用Maven构建项目为jar包 RUN mvn clean package # 使用Maven构建项目为jar包(跳过测试阶段) # RUN mvn clean package -DskipTests=true # 新的构建阶段 # 引入JDK17的基础镜像 FROM openjdk:17-jdk-slim # 设置工作目录,容器也会使用该目录作为工作目录 WORKDIR /app # 将 build 阶段构建jar包复制到新阶段的/app路径下 COPY --from=build /app/target/output-demo.jar app.jar # 设置在运行此镜像后默认执行的命令,让它运行刚才的jar包 ENTRYPOINT ["java", "-jar", "app.jar"] # 暴露端口,取决于项目实际使用的端口号 EXPOSE 8080

在Docker的多阶段构建中,每次使用新的 FROM 指令,都会开始一个新的构建阶段,上一阶段的指令会创建为一个临时的镜像。在新阶段中,前一阶段的层和设置都被丢弃,只有 --from 指定的之前阶段的内容被保留,就像是开始了一个全新的 Dockerfile 一样。

构建镜像

写好 Dockerfile 后,就可以通过该文件构建镜像了

 

bash

复制代码

docker build -t 仓库地址/命名空间/镜像名:标签 . docker build -t 仓库地址/命名空间/镜像名:标签 -f /path/myDockerfile .

-t 指定镜像名称(如果不推送到私有仓库,仅本地使用, 仓库地址/命名空间/ 可以省略)。

-f 指定 Dockerfile 所在的目录,也可以指定 自定义名称的Dockerfile-f 参数可省略)。

. 使用当前目录下作为上下文环境, COPY 等命令会从该目录查找文件。未指定 -f 参数时,则使用上下文环境中名为 Dockerfile 的文件。

推送镜像

每次发布更改内容都需要打包镜像后上传到生产环境再部署很麻烦,将镜像推送至私有仓库中,在生产环境直接从仓库中拉取镜像则更加高效。

 

bash

复制代码

# 登录仓库 docker login 仓库地址 # 推送镜像 docker push 仓库地址/命名空间/镜像名:标签

没有显式指定仓库地址时,默认会将DockerHub作为仓库地址。

层与缓存

层(Layers): 根据 Dockerfile 构建镜像时,每一个会改变文件系统状态的指令( RUNCOPY ADD 等)都会新建一个层 ,每个层都是前一层的改动的结果,并且每个层都只保留改动的部分,共享未改动的部分。依次将所有的层合并起来就是完成的镜像。

根据这个例子可以方便理解层的概念:

 

bash

复制代码

# Dockerfile A RUN apt-get install -y software-package # 第一层 RUN rm -rf /var/lib/apt/lists/* # 第二层

在这个片段中,第一层中安装了一个软件包,第二层中删除了软件包。

因为 每个层都是前一层的改动的结果 ,所以第二层的删除文件并不能影响到第一层,只是会在第二层中对该文件打上一个 删除 的标记,这个文件会作为一个无用的文件存在于最终构建的镜像中,增加了镜像的体积。

 

bash

复制代码

# Dockerfile B RUN apt-get install -y software-package && rm -rf /var/lib/apt/lists/*

在这个片段中,安装和删除软件包是在同一个指令下执行的,所以他们是处于同一层的操作,当这一层的构建结束时,这些文件就会被清理掉,它们也就不会存在于最终的镜像中了。


缓存: 缓存多个镜像之间可以共享层,如果多镜像都是基于同一个基础镜像进行构建的。那么,这个基础镜像的所有层都只需要存储一次,就能在所有的镜像中共享。如果一个镜像的大部分层已经在本地存在,那么在拉取这个镜像时,只有不存在的层需要被下载,这可以极大地节省时间和网络带宽。

Docker Compose

当项目依赖的服务较多时,每个容器都要单独配置运行,指定网络。使用Docker Compose,可以通过一个YAML文件定义服务,并同时运行它们。

Docker Compose将所管理的容器分为三层:工程(Project)、服务(Service)、容器(Container)。

通过一个例子来理解三层结构:

  1. 工程: 一个工程可以被视为一家公司,它为所有服务提供了整体的工作环境和资源配置。
  2. 服务: 公司内设有各种部门,如财务和行政等,每个部门有自己特定的职责和任务。每个部门都可以被看作一个服务。
  3. 容器: 每个部门由一个或多个员工组成。尽管每个员工都是独立的,但他们共享同样的环境。一个员工相当于一个容器。

所有部门都在同一家公司工作并使用该公司的资源,所以所有服务在工程中共享同样的网络、卷等资源

各个部门之间还是会进行交流和协作,所以各个服务之间可以互相通信

同一部门的所有员工都具有相同的工作环境,所以属于同一服务的所有容器都有统一的配置。员工各自做自己的项目,所以容器间有一定的隔离性

在要部署项目的目录创建一个 docker-compose.yml 文件:

 

yaml

复制代码

# 指定Docker Compose配置文件的版本 version: '3.8' services: # 定义应用服务,名为 app app: image: '仓库地址/命名空间/镜像名称:标签' # 将容器的8080端口映射到宿主机的8080端口 ports: - 8080:8080 volumes: # 将 docker-compose.yml 所在目录映射到容器中的 /app 目录(在 Dockerfile 中给定的工作目录) - ./:/app # 定义启动依赖,会先启动 mysqldb 和 redisdb,再启动 app depends_on: - mysqldb - redisdb # 指定容器启动后执行的命令 command: ["java", "-jar", "app.jar"] # 如果服务非手动停止,Docker会自动尝试重启服务 restart: always # 定义一个MySQL服务,名为 mysqldb # 其他服务连接MySQL数据库时,主机地址就是 mysqldb:3306 mysqldb: image: mysql:8.0.30 environment: - MYSQL_ROOT_PASSWORD=root volumes: - db_data:/var/lib/mysql # 定义一个Redis服务,名为 redisdb # 其他服务连接Redis数据库时,主机地址就是 redisdb:6379 redisdb: image: redis:7.2.4 volumes: - redis_data:/data volumes: db_data: redis_data:

docker-compose.yml 文件所在的目录执行

 

bash

复制代码

docker compose up -d

docker compose up 根据 docker-compose.yml 文件内容启动、创建、连接服务。

-d 参数表示以后台方式运行。

-f 如果文件名称不是 docker-compose.yml ,可以通过 -f 命令指定,使用方法与 构建镜像 章节一致。

每次更改了 docker-compose.yml 文件,都需要重新运行 docker-compose up -d 命令以应用更改。

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

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

相关文章

jmeter 中用python 实现请求参数的随机

首先需要下载插件来让jmeter支持python脚本 下载地址:https://www.jython.org/download,下载完成后放到jmeter安装目录的lib文件夹下 放置完成后需要重启jmeter,添加JSR223 PreProcessor,Language下拉框中多2项 选择第一项&#…

PyTorch基础(20)-- torch.gt() / torch.ge() / torch.le() / torch.lt()方法

一、前言 嗯……最近遇到的奇奇怪怪的方法很多了,学无止境啊!学不完啊,根本学不完!本篇文章介绍四个方法:torch.gt()、torch.ge()、torch.le()和torch.lt()方法,由于这四个方法很相似,所以放到…

四 超级数据查看器 讲解稿 列表功能1

四 超级数据查看器 讲解稿 列表功能1 点击此处 以新页面 打开B站 播放教学视频 APP下载地址 百度手机助手 下载地址4 讲解稿全文: 大家好,今天我们讲解一下,超级数据查看器列表界面,分为1-2两集。 首先&#xff0c…

RK3568 xhci主控挂死问题

串口日志 rootjenet:~# [18694.115430] xhci-hcd xhci-hcd.1.auto: xHCI host not responding to stop endpoint command. [18694.125667] xhci-hcd xhci-hcd.1.auto: xHCI host controller not responding, assume dead [18694.125977] xhci-hcd xhci-hcd.1.auto: HC died; c…

【数据分享】2000-2022年全国1km分辨率的逐年PM10栅格数据(免费获取)

空气质量数据是在我们日常研究中经常使用的数据!之前我们给大家分享了2000-2022年全国范围逐年的PM2.5栅格数据、2013-2022年全国范围逐年SO2栅格数据和2013-2022年全国范围逐年CO栅格数据(可查看之前的文章获悉详情)! 本次我们给…

[iOS]高版本MacOS运行低版本Xcode

Xcode 版本支持文档 目的: 在MacOS Sonoma 系统上安装 Xcode14.3.1 第一步 先在Xcode下载一个Xcode14.3.1的压缩包 第二步 本地解压Xcode,将外层目录名变更为Xcode_14.3.1,将文件拷贝到 /Applications目录下。 第三步 变更xcode-sel…

裸机编程的几种模式、架构与缺陷。

大多数嵌入式的初学者都是从单片机裸机编程开始的,对于初学者来说,裸机编程更加直观、简单,代码所见及所得,调试也非常方便,区别于使用操作系统需要先了解大量的操作系统基础知识,调度的基本常识&#xff0…

Redis及其数据类型和常用命令(一)

Redis 非关系型数据库,不需要使用sql语句对数据库进行操作,而是使用命令进行操作,在数据库存储时使用键值对进行存储,应用场景广泛。 一般关系型数据库(使用sql语句进行操作的数据库)和非关系型数据库可以…

每日一题 — 四数之和

18. 四数之和 - 力扣(LeetCode) 思路: 双指针思想,转换成三数之和,在转换成二数之和先排序,固定一个数a,转换成三数之和再固定一个数b,转换成二数之和再注意不漏和去重 代码&#…

[LeetCode][426]【学习日记】将二叉搜索树转化为排序的双向链表——前驱节点pre 和 当前节点cur 的使用

题目 426. 将二叉搜索树转化为排序的双向链表 将一个 二叉搜索树 就地转化为一个 已排序的双向循环链表 。 对于双向循环列表,你可以将左右孩子指针作为双向循环链表的前驱和后继指针,第一个节点的前驱是最后一个节点,最后一个节点的后继是第…

读算法的陷阱:超级平台、算法垄断与场景欺骗笔记07_价格歧视

1. 行为歧视 1.1. 单个企业通过使用数据驱动的算法,从而更好地实现锁定客户、开展个性化营销与定价的目的 1.2. 市场环境再次发生了变化 1.2.1. 在共谋场景中,定价算法提高了企业经营者在销量数据上的透明性&#xf…

【Java从入门到精通】Java异常处理

异常是程序中的一些错误,但并不是所有的错误都是异常,并且错误有时候是可以避免的。 比如说,你的代码少了一个分号,那么运行出来结果是提示是错误 java.lang.Error;如果你用System.out.println(11/0),那么…

Java并发编程: AQS

文章目录 一、前置知识二、什么是AQS三、使用AQS框架的锁和同步器1、ReentrantLock2、ReentrantReadWriteLock3、CountDownLatch4、CyclicBarrier5、Semaphore:信号量 四、锁和同步器的关系1、锁:面向锁的使用者2、同步器:面向锁的实现者 五、…

四川易点慧电子商务有限公司抖音小店安全正规

在如今网络购物日益普及的时代,消费者对于购物平台的选择越来越挑剔。四川易点慧电子商务有限公司抖音小店以其安全正规的经营模式,赢得了广大消费者的信赖和好评。本文将为您详细介绍四川易点慧电子商务有限公司抖音小店的优势和特点,让您在…

Vue3全家桶 - Vue3 - 【2】声明响应式数据(ref + reactive + toRef + toRefs)

声明响应式数据 一、 组合式API 1.1 ref() ref() 函数,可以创建 任何数据类型 的 响应式数据;🔺注意: 当值为 对象类型 时,会用 reactive() 自动转换它的 .value; ref 函数的内部实现依赖于 reactive 函…

【AI】如何创建自己的自定义ChatGPT

如何创建自己的自定义ChatGPT 目录 如何创建自己的自定义ChatGPT大型语言模型(LLM)GPT模型ChatGPTOpenAI APILlamaIndexLangChain参考推荐超级课程: Docker快速入门到精通Kubernetes入门到大师通关课本文将记录如何使用OpenAI GPT-3.5模型、LlamaIndex和LangChain创建自己的…

java-ssm-基于jsp商场停车服务管理信息系统

java-ssm-基于jsp商场停车服务管理信息系统

Notes用户还可自助改密码

大家好,才是真的好。 很多时候企业对员工的安全使用进行了硬性规定,例如严格的就是,每三个月或六个月要至少更改一次密码。 在Domino 8.5以后,功能上多了一个新特性,叫ID保险库,其实就是把用户的id标识符…

day40 整数拆分 不同的二叉搜索树

题目1&#xff1a;343 整数拆分 题目链接&#xff1a;343 整数拆分 题意 将正整数n拆成k个正整数的和&#xff08;k>2&#xff09;使整数的乘积最大化 尽量拆成若干个数值近似相等的数&#xff0c;这使用的是数学里面的思想&#xff1a;ab<(a^2b^2)/2 (当且仅当ab时&…

http升级https需要做什么

背景&#xff1a;随着现代网络时代的高速发展&#xff0c;网络安全方面的日益更新&#xff0c;实现网站https协议的数量也在不断增多&#xff0c;完善安全方面的因素也在逐步增加。 下面从最基础的网站http协议全面升级为https协议的流程做出说明。 目录 首先带大家一起先了解…