Docker 入门

news/2024/12/5 11:56:55/

文章目录

      • 安装 docker
      • docker inspect
      • Dockerfile 实例
      • 拷贝容器内的数据
      • 共享主机上的文件
      • 映射端口
      • 搭建私有镜像仓库
      • 搭建 WordPress 网站

安装 docker

以下操作都是在 Ubuntu 上进行。

sudo apt install -y docker.io
sudo service docker start         #启动docker服务
sudo usermod -aG docker ${USER}   #当前用户加入docker组

直接使用 root 用户不够安全,加入 Docker 用户组是一个比较好的选择,这也是 Docker 官方推荐的做法。当然,如果只是为了图省事,也可以直接切换到 root 用户来操作 Docker。

docker --version
# Docker version 20.10.12, build 20.10.12-0ubuntu4
docker info

docker inspect

docker inspect 查看镜像的分层信息:

root@ubuntu:/home/foxit# docker inspect busybox
[{"Id": "sha256:827365c7baf137228e94bcfc6c47938b4ffde26c68c32bf3d3a7762cd04056a5","RepoTags": ["busybox:latest"],"RepoDigests": ["busybox@sha256:05a79c7279f71f86a2a0d05eb72fcb56ea36139150f0a75cd87e80a4272e4e39"],"Parent": "","Comment": "","Created": "2022-12-22T19:33:52.928922607Z","Container": "6bb2277bf69d9f9b88e1557bd0f5321ac68fb8bcb6e4de5d92f42bddba5c9c40","ContainerConfig": {"Hostname": "6bb2277bf69d","Domainname": "","User": "","AttachStdin": false,"AttachStdout": false,"AttachStderr": false,"Tty": false,"OpenStdin": false,"StdinOnce": false,"Env": ["PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin"],"Cmd": ["/bin/sh","-c","#(nop) ","CMD [\"sh\"]"],"Image": "sha256:b48f24f21d3d973e503986bc9a3c5913acd65620d122644519f344eed8bcfb7f","Volumes": null,"WorkingDir": "","Entrypoint": null,"OnBuild": null,"Labels": {}},"DockerVersion": "20.10.12","Author": "","Config": {"Hostname": "","Domainname": "","User": "","AttachStdin": false,"AttachStdout": false,"AttachStderr": false,"Tty": false,"OpenStdin": false,"StdinOnce": false,"Env": ["PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin"],"Cmd": ["sh"],"Image": "sha256:b48f24f21d3d973e503986bc9a3c5913acd65620d122644519f344eed8bcfb7f","Volumes": null,"WorkingDir": "","Entrypoint": null,"OnBuild": null,"Labels": null},"Architecture": "amd64","Os": "linux","Size": 4859010,"VirtualSize": 4859010,"GraphDriver": {"Data": {"MergedDir": "/var/lib/docker/overlay2/5dbf3bb72c09509c16780071f736b70254137a3c8e3bd6c36b294ea6cb64bc71/merged","UpperDir": "/var/lib/docker/overlay2/5dbf3bb72c09509c16780071f736b70254137a3c8e3bd6c36b294ea6cb64bc71/diff","WorkDir": "/var/lib/docker/overlay2/5dbf3bb72c09509c16780071f736b70254137a3c8e3bd6c36b294ea6cb64bc71/work"},"Name": "overlay2"},"RootFS": {"Type": "layers","Layers": ["sha256:d6a7fc1fb44b63324d3fc67f016e1ef7ecc1a5ae6668ae3072d2e17230e3cfbc"]},"Metadata": {"LastTagTime": "0001-01-01T00:00:00Z"}}
]
root@ubuntu:/home/foxit# 

可以看出,镜像里有 1 个 Layer。

在使用 docker pull、docker rmi 等命令操作镜像的时候,那些“奇怪”的输出信息是什么了,其实就是镜像里的各个 Layer。Docker 会检查是否有重复的层,如果本地已经存在就不会重复下载,如果层被其他镜像共享就不会删除,这样就可以节约磁盘和网络成本。


Dockerfile 实例

一个最简单的 Dockerfile 实例

root@ubuntu:/home/test# touch Dockerfile
root@ubuntu:/home/test# vi Dockerfile 
root@ubuntu:/home/test# cat Dockerfile 
# Dockerfile.busybox
FROM busybox
CMD echo "hello world, Dockerfile."root@ubuntu:/home/test# docker build -f Dockerfile .
Sending build context to Docker daemon  2.048kB
Step 1/2 : FROM busybox---> 827365c7baf1
Step 2/2 : CMD echo "hello world, Dockerfile."---> Running in e479284067df
Removing intermediate container e479284067df---> c752945c7783
Successfully built c752945c7783

会看到 Docker 会逐行地读取并执行 Dockerfile 里的指令,依次创建镜像层,再生成完整的镜像。

新的镜像暂时还没有名字(用 docker images 会看到是 ),但我们可以直接使用“IMAGE ID”来查看或者运行:

root@ubuntu:/home/test# ls
Dockerfile
root@ubuntu:/home/test# docker images
REPOSITORY   TAG       IMAGE ID       CREATED         SIZE
<none>       <none>    c752945c7783   2 minutes ago   4.86MB
root@ubuntu:/home/test# docker inspect c75
[{"Id": "sha256:c752945c7783ccb24c9af06954754835a2d11f8baefed3f4337659fdc1612890","RepoTags": [],"RepoDigests": [],"Parent": "sha256:827365c7baf137228e94bcfc6c47938b4ffde26c68c32bf3d3a7762cd04056a5","Comment": "","Created": "2022-12-28T14:20:59.564595675Z","Container": "e479284067dfd9ac5a026745b79c093b859252a7fabb8dc9a7724a670a4698e6","ContainerConfig": {"Hostname": "e479284067df","Domainname": "","User": "","AttachStdin": false,"AttachStdout": false,"AttachStderr": false,"Tty": false,"OpenStdin": false,"StdinOnce": false,"Env": ["PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin"],"Cmd": ["/bin/sh","-c","#(nop) ","CMD [\"/bin/sh\" \"-c\" \"echo \\\"hello world, Dockerfile.\\\"\"]"],"Image": "sha256:827365c7baf137228e94bcfc6c47938b4ffde26c68c32bf3d3a7762cd04056a5","Volumes": null,"WorkingDir": "","Entrypoint": null,"OnBuild": null,"Labels": {}},"DockerVersion": "20.10.7","Author": "","Config": {"Hostname": "","Domainname": "","User": "","AttachStdin": false,"AttachStdout": false,"AttachStderr": false,"Tty": false,"OpenStdin": false,"StdinOnce": false,"Env": ["PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin"],"Cmd": ["/bin/sh","-c","echo \"hello world, Dockerfile.\""],"Image": "sha256:827365c7baf137228e94bcfc6c47938b4ffde26c68c32bf3d3a7762cd04056a5","Volumes": null,"WorkingDir": "","Entrypoint": null,"OnBuild": null,"Labels": null},"Architecture": "amd64","Os": "linux","Size": 4859010,"VirtualSize": 4859010,"GraphDriver": {"Data": {"MergedDir": "/var/lib/docker/overlay2/5dbf3bb72c09509c16780071f736b70254137a3c8e3bd6c36b294ea6cb64bc71/merged","UpperDir": "/var/lib/docker/overlay2/5dbf3bb72c09509c16780071f736b70254137a3c8e3bd6c36b294ea6cb64bc71/diff","WorkDir": "/var/lib/docker/overlay2/5dbf3bb72c09509c16780071f736b70254137a3c8e3bd6c36b294ea6cb64bc71/work"},"Name": "overlay2"},"RootFS": {"Type": "layers","Layers": ["sha256:d6a7fc1fb44b63324d3fc67f016e1ef7ecc1a5ae6668ae3072d2e17230e3cfbc"]},"Metadata": {"LastTagTime": "0001-01-01T00:00:00Z"}}
] 
root@ubuntu:/home/test# docker run c75
hello world, Dockerfile.
root@ubuntu:/home/foxit# docker ps -a
CONTAINER ID   IMAGE     COMMAND                   CREATED          STATUS                      PORTS     NAMES
0fafe002f112   c75       "/bin/sh -c 'echo \"h…"   9 seconds ago    Exited (0) 8 seconds ago              festive_hawking

把 Shell 命令集中到一个脚本文件里,用 COPY 命令拷贝进去再用 RUN 来执行:

root@ubuntu:/home/test# cat Dockerfile 
# Dockerfile.busybox
FROM busybox
CMD echo "hello world, Dockerfile."
COPY echo.sh /tmp/
RUN cd /tmp && chmod +x echo.sh \&& ./echo.shroot@ubuntu:/home/test# docker build -f Dockerfile .
Sending build context to Docker daemon  3.072kB
Step 1/4 : FROM busybox---> 827365c7baf1
Step 2/4 : CMD echo "hello world, Dockerfile."---> Using cache---> c752945c7783
Step 3/4 : COPY echo.sh /tmp/---> c53cd9825cfe
Step 4/4 : RUN cd /tmp && chmod +x echo.sh     && ./echo.sh---> Running in afd12463eb40
echo file, hello world.
Removing intermediate container afd12463eb40---> ab6668eb45ec
Successfully built ab6668eb45ec
# 窗口1,运行docker
root@ubuntu:/home/test# docker run -it --rm ab66 sh
/ # cd /tmp
/tmp # ls
echo.sh
/tmp # cat echo.sh 
echo "echo file, hello world."
/tmp # # 窗口2,查看进程
root@ubuntu:/home/test# docker ps 
CONTAINER ID   IMAGE     COMMAND   CREATED         STATUS         PORTS     NAMES
51555d033d04   ab66      "sh"      9 seconds ago   Up 8 seconds             boring_sutherland

加上一个 -t 参数,也就是指定镜像的标签(tag),这样 Docker 就会在构建完成后自动给镜像添加名字。当然,名字必须要符合上节课里的命名规范,用 : 分隔名字和标签,如果不提供标签默认就是“latest”。

root@ubuntu:/home/test# docker build -f Dockerfile .  -t demo:1.0
Sending build context to Docker daemon  3.072kB
Step 1/4 : FROM busybox---> 827365c7baf1
Step 2/4 : CMD echo "hello world, Dockerfile."---> Using cache---> c752945c7783
Step 3/4 : COPY echo.sh /tmp/---> Using cache---> c53cd9825cfe
Step 4/4 : RUN cd /tmp && chmod +x echo.sh     && ./echo.sh---> Using cache---> ab6668eb45ec
Successfully built ab6668eb45ec
Successfully tagged demo:1.0
REPOSITORY   TAG       IMAGE ID       CREATED          SIZE
demo         1.0       ab6668eb45ec   49 minutes ago   4.86MB

拷贝容器内的数据

docker cp 的用法很简单,很类似 Linux 的“cp”“scp”,指定源路径(src path)和目标路径(dest path)就可以了。如果源路径是宿主机那么就是把文件拷贝进容器,如果源路径是容器那么就是把文件拷贝出容器,注意需要用容器名或者容器 ID 来指明是哪个容器的路径。

先启动一个容器

root@ubuntu:/home/test# docker run -d --rm redis
e744c8e3bfedd7749bd9b31da527cf8043e6114a45d99bb328467c248860e9a1root@ubuntu:/home/test# docker ps
CONTAINER ID   IMAGE     COMMAND                  CREATED              STATUS              PORTS      NAMES
e744c8e3bfed   redis     "docker-entrypoint.s…"   About a minute ago   Up About a minute   6379/tcp   trusting_mcnulty

拷贝

root@ubuntu:/home/test# ls
Dockerfile  echo.sh
root@ubuntu:/home/test# docker cp echo.sh e74:/tmp
root@ubuntu:/home/test# 

查看

root@ubuntu:/home/foxit# docker exec -it e74 /bin/bash
root@e744c8e3bfed:/data# 
root@e744c8e3bfed:/# cd /tmp
root@e744c8e3bfed:/tmp# ls
root@e744c8e3bfed:/tmp# # 拷贝后查看
root@e744c8e3bfed:/tmp# ls 
echo.sh
root@e744c8e3bfed:/tmp# 

将容器里的文件拷贝出来到宿主机器

root@ubuntu:/home/test# ls
Dockerfile  echo.sh
root@ubuntu:/home/test# docker cp e74:/tmp/echo.sh ./echo1.sh
root@ubuntu:/home/test# ls
Dockerfile  echo.sh  echo1.sh

共享主机上的文件

docker -v

在 docker run 命令启动容器的时候使用 -v 参数就行,具体的格式是“宿主机路径:容器内路径”。

使用 -v 参数把本机的“/tmp”目录挂载到容器里的“/tmp”目录,也就是说让容器共享宿主机的“/tmp”目录:

root@ubuntu:/home/foxit# docker run -d --rm -v /tmp:/tmp redis
2689ac76c37019585b5020f244013abc8af89b3a7d792b6cf1ea03ffa21af5d8

用 docker exec 进入容器,查看一下容器内的“/tmp”目录,应该就可以看到文件与宿主机是完全一致的。

root@ubuntu:/home/test# docker exec -it 268 /bin/bash
root@2689ac76c370:/data# ls /tmp
abc-WbHO7F                                            multipart-511927656
abc-dsQux7                                            multipart-512898008
hsperfdata_jenkins                                    multipart-523748913
# ...

在容器里的“/tmp”目录下随便做一些操作,比如删除文件、建立新目录等等,再回头观察一下宿主机,会发现修改会即时同步,这就表明容器和宿主机确实已经共享了这个目录。

-v 参数挂载宿主机目录的这个功能,对于我们日常开发测试工作来说非常有用,我们可以在不变动本机环境的前提下,使用镜像安装任意的应用,然后直接以容器来运行我们本地的源码、脚本,非常方便。

举例:

本机上只有 Python2.7,但我想用 Python3 开发,如果同时安装 Python2 和 Python3 很容易就会把系统搞乱,所以可以这么做:

  1. 先使用 docker pull 拉取一个 Python3 的镜像,因为它打包了完整的运行环境,运行时有隔离,所以不会对现有系统的 Python2.7 产生任何影响。
  2. 在本地的某个目录编写 Python 代码,然后用 -v 参数让容器共享这个目录。
  3. 现在就可以在容器里以 Python3 来安装各种包,再运行脚本做开发了。
docker pull python:alpine
docker run -it --rm -v `pwd`:/tmp python:alpine sh

启动一个容器后,如果想后面接着用,就不用加 --rm 参数,通过 docker ps -a 查看历史容器 id,再通过 docker start id 来启动,想着曾经的容器配置了啥,曾经共享的路径也是共享的,短期内用就不用再操作一遍了。


映射端口

docker run -d -p 80:80 nginx:alpine
curl 127.1:80
curl 127.1:80 -I

搭建私有镜像仓库

docker pull registry
root@ubuntu:/home/foxit# docker run -d -p 5000:5000 registry
f2730af2923f620aa9ca55b5ecca029421f9d0fb987f52092b1e5647a4591827
root@ubuntu:/home/foxit# 
root@ubuntu:/home/foxit# docker ps 
CONTAINER ID   IMAGE      COMMAND                  CREATED          STATUS          PORTS                                       NAMES
f2730af2923f   registry   "/entrypoint.sh /etc…"   11 seconds ago   Up 10 seconds   0.0.0.0:5000->5000/tcp, :::5000->5000/tcp   pensive_beaver

将 nginx:apline 作为测试对象

root@ubuntu:/home/test# docker pull nginx:alpine
root@ubuntu:/home/test# docker images
REPOSITORY   TAG       IMAGE ID       CREATED       SIZE
nginx        alpine    1e415454686a   2 weeks ago   40.7MB

先检查一下 registry 里没有东西:

root@ubuntu:/tmp# curl 127.1:5000/v2/_catalog
{"repositories":[]}
root@ubuntu:/tmp# curl 127.1:5000/v2/nginx/tags/list
{"errors":[{"code":"NAME_UNKNOWN","message":"repository name not known to registry","detail":{"name":"nginx"}}]}

把“nginx:alpine”改成了“127.0.0.1:5000/nginx:alpine”:

root@ubuntu:/home/test# docker tag nginx:alpine 127.0.0.1:5000/nginx:alpine

这个镜像有了一个附加仓库地址的完整名字,就可以用 docker push 推上去了:

root@ubuntu:/home/test# docker push 127.0.0.1:5000/nginx:alpine 
The push refers to repository [127.0.0.1:5000/nginx]
9e173cdce044: Pushed 
f2d47996fdfa: Pushed 
c23f26e962bd: Pushed 
0511ab7e6edc: Pushed 
ec7e4a91c33b: Pushed 
1fee4bd55a85: Pushed 
ded7a220bb05: Pushed 
alpine: digest: sha256:0f4e03e4e0e854bafe7ce689a4c2476feb07a88a465bbc7d0f155dd89a6b00db size: 1781

验证是否已经成功推送,把刚才打标签的镜像删掉,再重新下载:

root@ubuntu:/home/test# docker rmi 127.0.0.1:5000/nginx:alpine
Untagged: 127.0.0.1:5000/nginx:alpine
Untagged: 127.0.0.1:5000/nginx@sha256:0f4e03e4e0e854bafe7ce689a4c2476feb07a88a465bbc7d0f155dd89a6b00dbroot@ubuntu:/home/test# docker images
REPOSITORY   TAG       IMAGE ID       CREATED       SIZE
nginx        alpine    1e415454686a   2 weeks ago   40.7MB
registry     latest    81c944c2288b   7 weeks ago   24.1MBroot@ubuntu:/home/test# docker pull 127.0.0.1:5000/nginx:alpine
alpine: Pulling from nginx
Digest: sha256:0f4e03e4e0e854bafe7ce689a4c2476feb07a88a465bbc7d0f155dd89a6b00db
Status: Downloaded newer image for 127.0.0.1:5000/nginx:alpine
127.0.0.1:5000/nginx:alpineroot@ubuntu:/home/test# docker images
REPOSITORY             TAG       IMAGE ID       CREATED       SIZE
127.0.0.1:5000/nginx   alpine    1e415454686a   2 weeks ago   40.7MB
nginx                  alpine    1e415454686a   2 weeks ago   40.7MB
registry               latest    81c944c2288b   7 weeks ago   24.1MB

这里 docker pull 确实完成了镜像下载任务,不过因为原来的层原本就已经存在,所以不会有实际的下载动作,只会创建一个新的镜像标签。

Docker Registry 提供了 RESTful API,也可以发送 HTTP 请求来查看仓库里的镜像,具体的端点信息可以参考官方文档(https://docs.docker.com/registry/spec/api/),分别获取了镜像列表和 Nginx 镜像的标签列表:

root@ubuntu:/home/test# curl 127.1:5000/v2/_catalog
{"repositories":["nginx"]}
root@ubuntu:/home/test# curl 127.1:5000/v2/nginx/tags/list
{"name":"nginx","tags":["alpine"]}

搭建 WordPress 网站

docker pull wordpress:5
docker pull mariadb:10
docker pull nginx:alpine

先来运行 MariaDB。根据说明文档,需要配置“MARIADB_DATABASE”等几个环境变量,用 --env 参数来指定启动时的数据库、用户名和密码,这里我指定数据库是“test_db”,用户名是“wp”,密码是“123”,管理员密码(root password)也是“123”。

docker run -d --rm \--env MARIADB_DATABASE=test_db \--env MARIADB_USER=wp \--env MARIADB_PASSWORD=123 \--env MARIADB_ROOT_PASSWORD=123 \mariadb:10

启动之后,使用 docker exec 命令,执行数据库的客户端工具“mysql”,验证数据库是否正常运行:

root@ubuntu:/tmp# docker ps
CONTAINER ID   IMAGE        COMMAND                  CREATED          STATUS         PORTS      NAMES
c5a132a570b2   mariadb:10   "docker-entrypoint.s…"   10 seconds ago   Up 9 seconds   3306/tcp   wizardly_lamarrroot@ubuntu:/tmp# docker exec -it c5a mysql -u wp -p
Enter password: 
Welcome to the MariaDB monitor.  Commands end with ; or \g.
Your MariaDB connection id is 3
Server version: 10.10.2-MariaDB-1:10.10.2+maria~ubu2204 mariadb.org binary distributionCopyright (c) 2000, 2018, Oracle, MariaDB Corporation Ab and others.Type 'help;' or '\h' for help. Type '\c' to clear the current input statement.MariaDB [(none)]> show databases;
+--------------------+
| Database           |
+--------------------+
| information_schema |
| test_db            |
+--------------------+
2 rows in set (0.001 sec)MariaDB [(none)]> show tables;
ERROR 1046 (3D000): No database selected
MariaDB [(none)]> 

查看IP地址

因为 Docker 的 bridge 网络模式的默认网段是“172.17.0.0/16”,宿主机固定是“172.17.0.1”,而且 IP 地址是顺序分配的,所以如果之前没有其他容器在运行的话,MariaDB 容器的 IP 地址应该就是“172.17.0.2”

root@ubuntu:/tmp# docker inspect c5a |grep IPAddress"SecondaryIPAddresses": null,"IPAddress": "172.17.0.2","IPAddress": "172.17.0.2",

现在数据库服务已经正常,该运行应用服务器 WordPress 了,它也要用 --env 参数来指定一些环境变量才能连接到MariaDB,注意“WORDPRESS_DB_HOST”必须是 MariaDB 的 IP 地址,否则会无法连接数据库:

docker run -d --rm \--env WORDPRESS_DB_HOST=172.17.0.2 \--env WORDPRESS_DB_USER=wp \--env WORDPRESS_DB_PASSWORD=123 \--env WORDPRESS_DB_NAME=test_db \wordpress:5

WordPress 容器在启动的时候并没有使用 -p 参数映射端口号,所以外界是不能直接访问的,我们需要在前面配一个 Nginx 反向代理,把请求转发给 WordPress 的 80 端口。

配置 Nginx 反向代理必须要知道 WordPress 的 IP 地址,同样可以用 docker inspect 命令查看,如果没有什么意外的话它应该是“172.17.0.3”

root@ubuntu:/tmp# docker ps
CONTAINER ID   IMAGE         COMMAND                  CREATED         STATUS         PORTS      NAMES
77d1be1bf0ca   wordpress:5   "docker-entrypoint.s…"   5 seconds ago   Up 4 seconds   80/tcp     wonderful_visvesvaraya
c5a132a570b2   mariadb:10    "docker-entrypoint.s…"   5 minutes ago   Up 5 minutes   3306/tcp   wizardly_lamarr
root@ubuntu:/tmp# 
root@ubuntu:/tmp# docker inspect 77d |grep IPAddress"SecondaryIPAddresses": null,"IPAddress": "172.17.0.3","IPAddress": "172.17.0.3",

写出如下的配置文件:

root@ubuntu:/home/test# pwd
/home/test
root@ubuntu:/home/test# cat wp.conf 
server {listen 80;default_type text/html;location / {proxy_http_version 1.1;proxy_set_header Host $host;proxy_pass http://172.17.0.3;}
}

有了这个配置文件,最关键的一步就来了,我们需要用 -p 参数把本机的端口映射到 Nginx 容器内部的 80 端口,再用 -v 参数把配置文件挂载到 Nginx 的“conf.d”目录下。这样,Nginx 就会使用刚才编写好的配置文件,在 80 端口上监听 HTTP 请求,再转发到 WordPress 应用:

docker run -d --rm \-p 80:80 \-v `pwd`/wp.conf:/etc/nginx/conf.d/default.conf \nginx:alpine
root@ubuntu:/tmp# docker ps
CONTAINER ID   IMAGE          COMMAND                  CREATED          STATUS          PORTS                                       NAMES
b2fe4f9f723a   nginx:alpine   "/docker-entrypoint.…"   18 seconds ago   Up 17 seconds   0.0.0.0:80->80/tcp, :::80->80/tcp   elastic_goodall
77d1be1bf0ca   wordpress:5    "docker-entrypoint.s…"   8 minutes ago    Up 8 minutes    80/tcp                                      wonderful_visvesvaraya
c5a132a570b2   mariadb:10     "docker-entrypoint.s…"   13 minutes ago   Up 13 minutes   3306/tcp                                    wizardly_lamarr

打开浏览器,输入 127.0.0.1,或者是虚拟机的 IP 地址(我这里是“http://192.168.202.130”),就可以看到 WordPress 的界面。



http://www.ppmy.cn/news/22502.html

相关文章

java 继承之上——动绑机制详解

一、前言 : 在java 面向对象三大特性——继承篇中&#xff0c;我们说过java 中查找方法的顺序为 : 本类方法—>父类方法—>更高一级的父类—>......Object(顶层父类) 。然而&#xff0c;在某些情况下&#xff0c;这样的原则也会被凌驾。今天我们要说的java动态绑定机制…

【MySQL】MySQL中的日期和时间函数有哪些?元宵节杭州灯光烟花秀你去看了吗?

日期函数元宵节灯光秀时间和日期函数获取当前日期的函数和获取当前时间的函数获取当前日期函数UNIX时间戳函数返回UTC日期的函数和返回UTC时间的函数获取月份的函数MONTH&#xff08;date&#xff09;和MONTHNAME&#xff08;date&#xff09;获取星期的函数DAYNAME&#xff08…

算法刷题-插入区间、杨辉三角、移除链表元素

文章目录插入区间杨辉三角移除链表元素插入区间 给你一个** 无重叠的**_ &#xff0c;_按照区间起始端点排序的区间列表。 在列表中插入一个新的区间&#xff0c;你需要确保列表中的区间仍然有序且不重叠&#xff08;如果有必要的话&#xff0c;可以合并区间&#xff09;。 示…

若依框架---PageHelper分页(十)

在前几天的文章中&#xff0c;我们介绍了PageHelper的分页方法&#xff0c;研读代码定位到了ExecutorUtil.pageQuery(...)方法&#xff0c;并阅读到了其中的部分代码。 今天我们将看到重要的SQL修改代码。 getPageSql 我们接着看代码&#xff1a; if (!dialect.beforePage(…

【数模比赛】2023美国大学生数学建模比赛(思路、代码......)

&#x1f4a5;&#x1f4a5;&#x1f49e;&#x1f49e;欢迎来到本博客❤️❤️&#x1f4a5;&#x1f4a5; &#x1f3c6;博主优势&#xff1a;&#x1f31e;&#x1f31e;&#x1f31e;博客内容尽量做到思维缜密&#xff0c;逻辑清晰&#xff0c;为了方便读者。 ⛳️座右铭&a…

cmake构建动态库

文章目录前言代码库文件代码测试代码Linux下测试前言 linux下的动态库/静态库&#xff0c;以前就知道咋构建&#xff1a;头文件与库的关系。最近写win下动态库的时候&#xff0c;有些细节与linux下有点不同。 所以这篇文章简单介绍下&#xff0c;如果使用cmake构建一个可以跨…

git命令总结

1、git stash命令总结 git stash:命令会把所有未提交的修改保存到git堆栈&#xff08;包括git add和未add的&#xff09;。 git stash save "test-cmd-stash"&#xff1a;作用同上&#xff0c;但可以给stash添加注释信息。 git stash --keep-inde&#xff1a;只会…

HTML基础学习(3)——认识表格

往期文章 HTML基础学习&#xff08;1&#xff09;——HTML基本标签HTML基础学习&#xff08;2&#xff09;——超链接和使用图像 # 1.表格基本组成 HTML中表格使用表格标签\和多个行\、表头\ 或单元格\组成。 标签描述<table>定义表格<caption>定义表格标题<…