柒索

一个头脑聪明,五肢发达的男人。

0%

CentOS6.5 中默认安装了 Python,版本比较低,为了使用新版 3.x,需要对旧版本进行升级。

由于很多基本的命令、软件包都依赖旧版本,比如:yum。所以,在更新 Python 时,建议不要删除旧版本(新旧版本可以共存)。

查看 Python 版本号

当 Linux 上安装 Python 后(默认安装),只需要输入简单的命令,就可以查看 Python 的版本号:

1
2
3
python -V
# 或者
python --version

下载新版本

进入 Python下载页面,选择需要的版本。

这里,我选择的版本是 3.6.3 。

进入 /usr/local/src 目录

1
2
cd /usr/local/src/
wget https://www.python.org/ftp/python/3.6.3/Python-3.6.3.tgz

解压缩

下载完成之后,进行解压缩:

1
tar -zxvf Python-3.6.3.tgz

配置、编译、安装

安装openssl-devel(pip需要)

1
# yum install openssl-devel

进入解压缩后的目录,安装配置:

1
2
cd Python-3.6.3/
./configure

配置完成之后,就可以编译安装了:

1
2
3
4
# 编译
make
# 安装
make install

验证

安装成功以后,就可以查看 Python 的版本了:

1
2
3
4
# python -V
Python 2.7.5
# python3 -V
Python 3.5.2

注意:在 /usr/local/bin/ 下有一个 python3 的链接,指向 bin 目录下的 python 3.6。

设置 3.x 为默认版本

查看 Python 的路径,在 /usr/bin 下面。可以看到 python 链接的是 python 2.6,所以,执行 python 就相当于执行 python 2.6。

1
2
3
4
5
# ls -al /usr/bin | grep python
-rwxr-xr-x. 1 root root 11216 12月 1 2015 abrt-action-analyze-python
lrwxrwxrwx. 1 root root 7 8月 30 12:11 python -> python2
lrwxrwxrwx. 1 root root 9 8月 30 12:11 python2 -> python2.6
-rwxr-xr-x. 1 root root 7136 11月 20 2015 python2.6

将原来 python 的软链接重命名:

1
# mv /usr/bin/python /usr/bin/python.bak

将 python 链接至 python3:

1
# ln -s /usr/local/bin/python3 /usr/bin/python

再查看 Python 的版本:

1
2
# python -V
Python 3.6.3

输出的是 3.x,说明已经使用的是 python3了。

配置 yum

升级 Python 之后,由于将默认的 python 指向了 python3,yum 不能正常使用,需要编辑 yum 的配置文件:

1
# vi /usr/bin/yum

将 #!/usr/bin/python 改为 #!/usr/bin/python2.6,保存退出即可。

除了使用java -jar运行Spring Boot应用程序外,还可以为Unix系统打包完全可执行的应用程序。 这使得在常见的生产环境中安装和管理Spring Boot应用程序非常容易。

Spring Boot 提供了一个tools工具,该工具可以方便的让我们将程序部署到生产环境,本文将结合官网与实际项目部署,给出一个完美的部署方案。

将应用程序打包为执行的jar包

要使用Maven创建“完全可执行”的jar,请使用以下插件配置:

1
2
3
4
5
6
7
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<configuration>
<executable>true</executable>
</configuration>
</plugin>

这里的“完全可执行”实际上是Spring Boot tools在打包的过程中将bash脚本及一些辅助进行启动的Java代码打包到我们的项目中,这样

使用Gradle:

1
2
3
springBoot {
executable = true
}

然后,您可以通过键入./my-application.jar(其中my-application是您工程的artifact的名称)来运行应用程序。

完全可执行的jar通过在文件的前面嵌入一个额外的脚本来工作。 并不是所有的工具目前都接受这种格式,所以你可能并不总是能够使用这种技术。

默认脚本支持大多数Linux发行版,并在CentOS和Ubuntu上进行了测试。 其他平台,如OS X和FreeBSD,将需要使用自定义的embeddedLaunchScript。

当运行完全可执行的jar时,它将使用jar的目录作为工作目录。

Unix/Linux 服务

Spring Boot应用程序可以使用init.d或systemd轻松地作为Unix / Linux服务启动。

作为init.d服务进行安装(System V)

如果您配置了Spring Boot的Maven或Gradle插件来生成完全可执行的jar,并且您没有使用自定义的embeddedLaunchScript,那么您的应用程序可以用作init.d服务。 简单地将jar链接到init.d以支持标准的start,stop,restart和status命令。

该脚本支持以下功能:

  • 以拥有该jar文件的用户启动服务
  • 使用/var/run//.pid跟踪应用程序的PID
  • 将控制台日志写入/var/log/.log

假设你有一个Spring Boot应用程序安装在 /var/myapp 中,安装Spring Boot应用程序作为init.d服务只需创建一个符号链接:

1
sudo ln -s /var/myapp/myapp.jar /etc/init.d/myapp

一旦安装,您可以按照Linux系统常用的方式启动和停止服务。 例如,在基于Debian的系统上:

1
$ service myapp start

如果您的应用程序无法启动,请检查写入/var/log/.log的日志文件是否有错误日志。

您还可以将应用程序标记为使用标准操作系统工具自动启动。 例如Debian:

1
$ update-rc.d myapp defaults <priority>

保护init.d服务

以下是关于如何保护作为init.d服务运行的Spring Boot应用程序的一组指导。 它并不是为了强化应用程序和运行环境而应该做的所有事情的详尽列表。

当以root身份执行时,如使用root用于启动init.d服务的情况,默认可执行脚本将以拥有该jar文件的用户身份运行应用程序。 您不应该以root身份运行Spring Boot应用程序,因此您的应用程序的jar文件不应该由root拥有。 相反,创建一个特定的用户来运行应用程序,并使用chown将其作为jar文件的所有者。 例如:

1
$ chown bootapp:bootapp your-app.jar

在这种情况下,默认的可执行脚本将作为bootapp用户运行应用程序。

为了减少应用程序的用户帐户遭到入侵的机会,您应该考虑防止其使用登录shell。 例如,将帐户的shell设置为 /usr/sbin/nologin 。

您还应该采取措施来阻止修改jar文件。 首先,配置其权限,使其不能被写入,并且只能由其所有者读取或执行:

1
$ chmod 500 your-app.jar

其次,如果您的应用程序或运行它的帐户被泄露,您还应该采取措施限制jar包被损坏。如果攻击者获得访问权限,他们可以使jar文件可写,并更改其内容。防止这种情况的一种方法是使用chattr使其变得不可变:

1
$ sudo chattr +i your-app.jar

这将阻止任何用户(包括root)修改该jar。

如果使用root来控制应用程序的服务,并且使用.conf文件来自定义其启动,那么root用户将读取和评估该.conf文件。 应该保证相应的安全。 使用chmod,以便该文件只能由所有者读取,并使用chown使root成为所有者:

1
2
$ chmod 400 your-app.conf
$ sudo chown root:root your-app.conf

作为systemd服务进行安装

Systemd是System V init系统的后继者,现在被许多现代Linux发行版使用。尽管您可以继续使用systemd的init.d脚本,但也可以使用systemd’service’脚本启动Spring Boot应用程序。

假设您在 /var/myapp 中安装了一个Spring Boot应用程序,要将Spring Boot应用作为系统服务安装为使用以下示例创建名为myapp.service的脚本,并将其放在 /etc/systemd/system 目录中:

1
2
3
4
5
6
7
8
9
10
11
[Unit]
Description=myapp
After=syslog.target

[Service]
User=myapp
ExecStart=/var/myapp/myapp.jar
SuccessExitStatus=143

[Install]
WantedBy=multi-user.target

请记住更改应用程序的Description,User 和ExecStart 字段。

请注意,ExecStart字段不声明脚本操作命令,这意味着默认情况下使用run命令。

请注意,与运行init.d服务不同,运行应用程序,PID文件和控制台日志文件的用户由systemd本身管理,因此必须使用“service”脚本中的相应字段进行配置。 有关详细信息,请参阅服务单元配置手册页。

请注意,与运行init.d服务不同,运行应用程序,PID文件和控制台日志文件的用户由systemd本身管理,因此必须使用“service”脚本中的相应字段进行配置。 有关详细信息,请参阅服务单元配置手册页

要将应用程序标记为在系统启动时自动启动,请使用以下命令:

1
$ systemctl enable myapp.service

有关详细信息,请参阅man systemctl。

自定义启动脚本

由Maven或Gradle插件编写的默认嵌入式启动脚本可以通过多种方式进行自定义。 对于大多数人来说,使用默认脚本以及一些自定义项通常就足够了。 如果您发现无法自定义需要的内容,则可以随时使用embeddedLaunchScript选项来完全编写自己的文件。

编写自定义脚本

在将起始脚本写入jar文件时,自定义元素是很有意义的。 例如,init.d脚本可以提供一个“描述”,因为你知道这一点(它不会改变),你可以在生成jar时提供它。

打开终端

1
2
cd
vim .bash_profile

输入以下

1
2
3
4
5
export JAVA_7_HOME=`/usr/libexec/java_home -v 1.7`
export JAVA_8_HOME=`/usr/libexec/java_home -v 1.8`
export JAVA_HOME=$JAVA_8_HOME
alias jdk7="export JAVA_HOME=$JAVA_7_HOME"
alias jdk8="export JAVA_HOME=$JAVA_8_HOME"

Mac OSX 10.5+ 以后,官方建议$JAVA_HOME的设置用 /usr/libexec/java_home 代替
也可以写绝对路径,通过echo $JAVA_HOME 查看JDK路径
例如

1
2
export JAVA_7_HOME="/Library/Java/JavaVirtualMachines/jdk1.7.0_79.jdk/Contents/Home"
export JAVA_8_HOME="/Library/Java/JavaVirtualMachines/jdk1.8.0_111.jdk/Contents/Home"

修改完成后,保存重新编译

1
source ~/.bash_profile

在终端中输入jdk7、jdk8 切换版本,通过java -version 查看版本

搭建伪分布式Hadoop环境

环境说明

  • CentOS 7.2 64 位
  • OpenJDK- 1.8
  • Hadoop- 2.7

安装 SSH 客户端

安装SSH

安装SSH:

1
sudo yum install openssh-clients openssh-server

安装完成后,可以使用下面命令进行测试:

1
ssh localhost

输入 root 账户的密码,如果可以正常登录,则说明SSH安装没有问题。测试正常后使用 exit 命令退出ssh。

免密登录

配置免密码登录:

1

安装 JAVA 环境

安装 JDK

使用 yum 来安装1.7版本 OpenJDK:

1
sudo yum install java-1.8.0-openjdk java-1.8.0-openjdk-devel

安装完成后,输入 javajavac 命令,如果能输出对应的命令帮助,则表明jdk已正确安装。

配置 JAVA 环境变量

执行命令:

编辑 ~/.bashrc,在结尾追加:

1
export JAVA_HOME=/usr/lib/jvm/java-1.8.0-openjdk

保存文件后执行下面命令使 JAVA_HOME 环境变量生效:

1
source ~/.bashrc

为了检测系统中 JAVA 环境是否已经正确配置并生效,可以分别执行下面命令:

1
2
java -version
$JAVA_HOME/bin/java -version

若两条命令输出的结果一致,且都为我们前面安装的 openjdk-1.8.0 的版本,则表明 JDK 环境已经正确安装并配置。

安装 Hadoop

下载 Hadoop

本教程使用 hadoop-2.7 版本,使用 wget 工具在线下载(注:本教程是从清华大学的镜像源下载,如果下载失败或报错,可以自己在网上找到国内其他一个镜像源下载 2.7 版本的 hadoop 即可):

1
wget https://archive.apache.org/dist/hadoop/common/hadoop-2.7.4/hadoop-2.7.4.tar.gz

安装 Hadoop

将 Hadoop 安装到 /usr/local 目录下:

1
tar -zxf hadoop-2.7.4.tar.gz -C /usr/local

对安装的目录进行重命名,便于后续操作方便:

1
2
cd /usr/local
mv ./hadoop-2.7.4/ ./hadoop

检查Hadoop是否已经正确安装:

1
/usr/local/hadoop/bin/hadoop version

如果成功输出hadoop的版本信息,表明hadoop已经成功安装。

Hadoop 伪分布式环境配置

Hadoop伪分布式模式使用多个守护线程模拟分布的伪分布运行模式。

设置 Hadoop 的环境变量

编辑 ~/.bashrc,在结尾追加如下内容:

1
2
3
4
5
6
7
8
export HADOOP_HOME=/usr/local/hadoop
export HADOOP_INSTALL=$HADOOP_HOME
export HADOOP_MAPRED_HOME=$HADOOP_HOME
export HADOOP_COMMON_HOME=$HADOOP_HOME
export HADOOP_HDFS_HOME=$HADOOP_HOME
export YARN_HOME=$HADOOP_HOME
export HADOOP_COMMON_LIB_NATIVE_DIR=$HADOOP_HOME/lib/native
export PATH=$PATH:$HADOOP_HOME/sbin:$HADOOP_HOME/bin

使Hadoop环境变量配置生效:

1
source ~/.bashrc

修改 Hadoop 的配置文件

Hadoop的配置文件位于安装目录的 /etc/hadoop 目录下,在本文中即位于 /url/local/hadoop/etc/hadoop 目录下,需要修改的配置文件为如下两个:

1
2
/usr/local/hadoop/etc/hadoop/core-site.xml
/usr/local/hadoop/etc/hadoop/hdfs-site.xml

修改core-site.xml节点的内容为如下所示:;

1
2
3
4
5
6
7
8
9
10
11
<configuration>
<property>
<name>hadoop.tmp.dir</name>
<value>file:/usr/local/hadoop/tmp</value>
<description>location to store temporary files</description>
</property>
<property>
<name>fs.defaultFS</name>
<value>hdfs://localhost:9000</value>
</property>
</configuration>

修改hdfs-site.xml节点的内容为如下所示:;

1
2
3
4
5
6
7
8
9
10
11
12
13
14
<configuration>
<property>
<name>dfs.replication</name>
<value>1</value>
</property>
<property>
<name>dfs.namenode.name.dir</name>
<value>file:/usr/local/hadoop/tmp/dfs/name</value>
</property>
<property>
<name>dfs.datanode.data.dir</name>
<value>file:/usr/local/hadoop/tmp/dfs/data</value>
</property>
</configuration>

格式化NameNode:

1
/usr/local/hadoop/bin/hdfs namenode -format

在输出信息中看到如下信息,则表示格式化成功:

1
2
Storage directory /usr/local/hadoop/tmp/dfs/name has been successfully formatted.
Exiting with status 0

启动 NameNode 和 DataNode 守护进程

启动 NameNode 和 DataNode 进程:

1
/usr/local/hadoop/sbin/start-dfs.sh

执行过程中会提示输入用户密码,输入 root 用户密码即可。另外,启动时ssh会显示警告提示是否继续连接,输入 yes 即可。

检查 NameNode 和 DataNode 是否正常启动:

1
jps

如果NameNode和DataNode已经正常启动,会显示NameNode、DataNode和SecondaryNameNode的进程信息:

1
2
3
4
5
[hadoop@VM_80_152_centos ~]$ jps
3689 SecondaryNameNode
3520 DataNode
3800 Jps
3393 NameNode

运行 Hadoop 伪分布式实例

Hadoop自带了丰富的例子,包括 wordcount、grep、sort 等。下面我们将以grep例子为教程,输入一批文件,从中筛选出符合正则表达式 dfs[a-z.]+ 的单词并统计出现的次数。

查看 Hadoop 自带的例子

Hadoop 附带了丰富的例子, 执行下面命令可以查看:

1
2
3
cd /usr/local/hadoop
./bin/hadoop jar ./share/hadoop/mapreduce/hadoop-mapreduce-examples-2.7.4.jar

在 HDFS 中创建用户目录

在 HDFS 中创建用户目录 hadoop:

1
/usr/local/hadoop/bin/hdfs dfs -mkdir -p /user/hadoop

准备实验数据

本教程中,我们将以 Hadoop 所有的 xml 配置文件作为输入数据来完成实验。执行下面命令在 HDFS 中新建一个 input 文件夹并将 hadoop 配置文件上传到该文件夹下:

1
2
3
cd /usr/local/hadoop
./bin/hdfs dfs -mkdir /user/hadoop/input
./bin/hdfs dfs -put ./etc/hadoop/*.xml /user/hadoop/input

使用下面命令可以查看刚刚上传到 HDFS 的文件:

1
/usr/local/hadoop/bin/hdfs dfs -ls /user/hadoop/input

运行实验

运行实验:

1
2
cd /usr/local/hadoop
./bin/hadoop jar ./share/hadoop/mapreduce/hadoop-mapreduce-examples-2.7.4.jar grep /user/hadoop/input /user/hadoop/output &#39;dfs[a-z.]+&#39;

上述命令以 HDFS 文件系统中的 input 为输入数据来运行 Hadoop 自带的 grep 程序,提取其中符合正则表达式 dfs[a-z.]+ 的数据并进行次数统计,将结果输出到 HDFS 文件系统的 output 文件夹下。

查看运行结果

上述例子完成后的结果保存在 HDFS 中,通过下面命令查看结果:

1
/usr/local/hadoop/bin/hdfs dfs -cat /user/hadoop/output/*

如果运行成功,可以看到如下结果:

1
2
3
4
1       dfsadmin
1 dfs.replication
1 dfs.namenode.name.dir
1 dfs.datanode.data.dir

删除 HDFS 上的输出结果

删除 HDFS 中的结果目录:

1
/usr/local/hadoop/bin/hdfs dfs -rm -r /user/hadoop/output

运行 Hadoop 程序时,为了防止覆盖结果,程序指定的输出目录不能存在,否则会提示错误,因此在下次运行前需要先删除输出目录。

关闭 Hadoop 进程

关闭 Hadoop 进程:

1
/usr/local/hadoop/sbin/stop-dfs.sh

再起启动只需要执行下面命令:

1
/usr/local/hadoop/sbin/start-dfs.sh

部署完成

简介

什么是Harbor

Harbor is an open source container image registry that secures images with role-based access control, scans images for vulnerabilities, and signs images as trusted. A CNCF Incubating project, Harbor delivers compliance, performance, and interoperability to help you consistently and securely manage images across cloud native compute platforms like Kubernetes and Docker.

Harbor是一个用于存储和分发Docker镜像的企业级Registry服务器。

安装要求

目标主机需要Docker和Docker Compose才能安装Harbor

硬件要求

资源 最低要求 官方推荐
CPU 2 CPU 4 CPU
Mem 4 GB 8 GB
Disk 40 GB 160 GB

软件要求

软件 版本
Docker engine 17.06.0-ce 以上或者更高
Docker Compose 1.18.0 以上或者更高
Openssl 最新版优先

Openssl用于生成Harbor的证书和密钥

主机配置

Vagrantfile

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
# -*- mode: ruby -*-
# vi: set ft=ruby :

Vagrant.require_version ">=1.6.0"
boxes = [
{
:name => "dk", #主机名
:eth1 => "192.168.22.22", #Ip
:mem => "4096", #内存
:cpu => "4" #核心数
}
]

Vagrant.configure("2") do |config|
config.vm.box = "centos-7.7"
config.disksize.size='40G'
boxes.each do |opts|
config.vm.define opts[:name] do |config|
config.vm.hostname = opts[:name]
config.vm.provider "virtualbox" do |v|
v.customize ["modifyvm", :id, "--memory", opts[:mem]]
v.customize ["modifyvm", :id, "--cpus", opts[:cpu]]
end
config.vm.network :private_network,ip: opts[:eth1]
end
end
# config.vm.network "public_network", ip: "192.168.10.11"
config.vm.provision "shell", privileged: true, path: "./config.sh"
config.vm.synced_folder "~/Share", "/home/vagrant/labs" #共享目录
end

安装过程

基础环境安装

Docker-ce

参考: https://developer.aliyun.com/mirror/docker-ce

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
# step 1: 安装必要的一些系统工具
[root@dk ~]# yum install -y yum-utils device-mapper-persistent-data lvm2
# Step 2: 添加软件源信息
[root@dk ~]# yum-config-manager --add-repo https://mirrors.aliyun.com/docker-ce/linux/centos/docker-ce.repo
# Step 3: 更新并安装Docker-CE
[root@dk ~]# yum makecache fast
[root@dk ~]# yum -y install docker-ce
# Step 4: 配置Docker镜像加速
[root@dk ~]# mkdir -p /etc/docker
[root@dk ~]# tee /etc/docker/daemon.json <<-'EOF'
{
"registry-mirrors": ["https://********.mirror.aliyuncs.com"]
}
EOF
[root@dk ~]# systemctl daemon-reload

# Step 5: 重启Docker服务
[root@dk ~]# systemctl restart docker

# 注意:
# 官方软件源默认启用了最新的软件,您可以通过编辑软件源的方式获取各个版本的软件包。例如官方并没有将测试版本的软件源置为可用,您可以通过以下方式开启。同理可以开启各种测试版本等。
# vim /etc/yum.repos.d/docker-ee.repo
# 将[docker-ce-test]下方的enabled=0修改为enabled=1
#
# 安装指定版本的Docker-CE:
# Step 1: 查找Docker-CE的版本:
# yum list docker-ce.x86_64 --showduplicates | sort -r
# Loading mirror speeds from cached hostfile
# Loaded plugins: branch, fastestmirror, langpacks
# docker-ce.x86_64 17.03.1.ce-1.el7.centos docker-ce-stable
# docker-ce.x86_64 17.03.1.ce-1.el7.centos @docker-ce-stable
# docker-ce.x86_64 17.03.0.ce-1.el7.centos docker-ce-stable
# Available Packages
# Step2: 安装指定版本的Docker-CE: (VERSION例如上面的17.03.0.ce.1-1.el7.centos)
# sudo yum -y install docker-ce-[VERSION]

验证:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
[root@dk ~]# docker version
Client: Docker Engine - Community
Version: 19.03.5
API version: 1.40
Go version: go1.12.12
Git commit: 633a0ea
Built: Wed Nov 13 07:25:41 2019
OS/Arch: linux/amd64
Experimental: false

Server: Docker Engine - Community
Engine:
Version: 19.03.5
API version: 1.40 (minimum version 1.12)
Go version: go1.12.12
Git commit: 633a0ea
Built: Wed Nov 13 07:24:18 2019
OS/Arch: linux/amd64
Experimental: false
containerd:
Version: 1.2.10
GitCommit: b34a5c8af56e510852c35414db4c1f4fa6172339
runc:
Version: 1.0.0-rc8+dev
GitCommit: 3e425f80a8c931f88e6d94a8c831b9d5aa481657
docker-init:
Version: 0.18.0
GitCommit: fec3683

Docker-Compose

参考:https://docs.docker.com/compose/install/

1
2
3
4
# step 1: 安装docker-compose
[root@dk ~]# curl -L "https://github.com/docker/compose/releases/download/1.25.0/docker-compose-$(uname -s)-$(uname -m)" -o /usr/local/bin/docker-compose
# step 2: 配置权限
[root@dk ~]# chmod +x /usr/local/bin/docker-compose

验证:

1
2
3
4
5
[root@dk ~]# docker-compose version
docker-compose version 1.25.0, build 0a186604
docker-py version: 4.1.0
CPython version: 3.7.4
OpenSSL version: OpenSSL 1.1.0l 10 Sep 2019

安装Harbor

Harbor为我们提供了两种安装方式 Online(在线) 、Offline(离线),使用离线安装的方式需要从Github上下载相关的安装包 大约600M,速度非常慢,此处我们选择在线安装的方式,此处由于配置了镜像加速器的原因,相对于离线安装的方式会快很多。

下载安装

下载完成后解压此文件,会出现Harbor目录

1
[root@dk ~]# wget https://github.com/goharbor/harbor/releases/download/v1.9.3/harbor-online-installer-v1.9.3.tgz
1
2
3
4
5
[root@dk ~]# tar  -xvf harbor-online-installer-v1.9.3.tgz
harbor/prepare
harbor/LICENSE
harbor/install.sh
harbor/harbor.yml

修改配置

进入到Harbor目录中修改harbor.yml文件,配置如下

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
hostname: 192.168.22.22
http:
port: 8888
harbor_admin_password: root
database:
password: root
max_idle_conns: 50
max_open_conns: 100
data_volume: /data
clair:
updaters_interval: 12
jobservice:
max_job_workers: 10
notification:
webhook_job_max_retry: 10
chart:
absolute_url: disabled
log:
level: info
local:
rotate_count: 50
rotate_size: 200M
location: /var/log/harbor
_version: 1.9.0
proxy:
http_proxy:
https_proxy:
no_proxy: 127.0.0.1,localhost,.local,.internal,log,db,redis,nginx,core,portal,postgresql,jobservice,registry,registryctl,clair
components:
- core
- jobservice
- clair

执行启动

进入到Harbor目录下,执行 ./prepare 确认无误后,在执行 ./install脚本

1
2
[root@dk ~]# ./prepare
[root@dk ~]# ./install

访问地址:

访问 harbor.yml中配置的hostname 即可以访问Harbor服务了

http://192.168.22.22:8888/

参考资料

Harbor官方网站: https://goharbor.io/

Harbor安装文档: https://github.com/goharbor/harbor/blob/master/docs/installation_guide.md

环境简介

名称 版本
VirtualBox.app 6.0.10
Vagrant 2.2.3
CentOS 7.6
Etcd 3.3.11
Kubernetes v1.5.2

虚拟机相关配置参考Vagrantfile.

环境准备

Vagrantfile:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
# -*- mode: ruby -*-
# vi: set ft=ruby :

Vagrant.require_version ">= 1.6.0"

boxes = [
{
:name => "k8s-master",
:eth1 => "192.168.11.21",
:mem => "1024",
:cpu => "1"
},
{
:name => "k8s-node1",
:eth1 => "192.168.11.22",
:mem => "1024",
:cpu => "1"
},
{
:name => "k8s-node2",
:eth1 => "192.168.11.23",
:mem => "1024",
:cpu => "1"
}
]

Vagrant.configure(2) do |config|

config.vm.box = "centos-7.6"

boxes.each do |opts|
config.vm.define opts[:name] do |config|
config.vm.hostname = opts[:name]
config.vm.provider "vmware_fusion" do |v|
v.vmx["memsize"] = opts[:mem]
v.vmx["numvcpus"] = opts[:cpu]
end

config.vm.provider "virtualbox" do |v|
v.customize ["modifyvm", :id, "--memory", opts[:mem]]
v.customize ["modifyvm", :id, "--cpus", opts[:cpu]]
end

config.vm.network :private_network, ip: opts[:eth1]
end
end
end

创建完成之后分别为三台机器更新yum源和epel源:

1
2
3
curl -o /etc/yum.repos.d/CentOS-Base.repo http://mirrors.aliyun.com/repo/Centos-7.repo
curl -o /etc/yum.repos.d/epel.repo http://mirrors.aliyun.com/repo/epel-7.repo
yum makecache

分别修改三台机器的 /etc/hosts文件,添加以下内容,使得三台机器之间可以互相访问:

1
2
3
192.168.11.21 k8s-master
192.168.11.22 k8s-node1
192.168.11.23 k8s-node2

修改完成之后测试是否可以互通。

开始搭建

为Master节点安装配置etcd

yum安装etcd:

1
[root@k8s-master ~]# yum install etcd -y  # 安装etcd

修改etcd配置文件:

1
2
3
[root@k8s-master ~]# vim /etc/etcd/etcd.conf  # 修改配置文件
ETCD_LISTEN_CLIENT_URLS="http://0.0.0.0:2379" # 第6行
ETCD_ADVERTISE_CLIENT_URLS="http://192.168.11.21:2379" # 第21行

设置etcd开机启动&启动etcd:

1
2
[root@k8s-master ~]# systemctl start etcd.service  # 启动etcd
[root@k8s-master ~]# systemctl enable etcd.service # 设置开启启动

测试etcd服务是否健康:

1
2
[root@k8s-master ~]# etcdctl -C http://192.168.11.21:2379 cluster-health                   
member 8e9e05c52164694d is healthy: got healthy result from http://192.168.11.21:2379 cluster is healthy

为Master节点安装Kubernetes

使用yum安装kubernetes:

1
[root@k8s-master ~]# yum install kubernetes-master.x86_64 -y

修改kubernetes的apiserver的配置文件:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
[root@k8s-master ~]# vim /etc/kubernetes/apiserver  :set nu 

# 第8行 将默认值修改为0.0.0.0
KUBE_API_ADDRESS="--insecure-bind-address=0.0.0.0"
# 第11行 打开注释
KUBE_API_PORT="--port=8080"
# 第14行 打开注释
KUBELET_PORT="--kubelet-port=10250"
#第17行 将默认值修改为master节点ip
KUBE_ETCD_SERVERS="--etcd-servers=http://192.168.11.21:2379"
# 第23行 删掉ServiceAccount内容
KUBE_ADMISSION_CONTROL="--admission-control=NamespaceLifecycle,NamespaceExists,LimitRanger,SecurityContextDeny,ResourceQuota"


修改kubernetes的配置文件:

1
2
[root@k8s-master ~]# vim /etc/kubernetes/config  
KUBE_MASTER="--master=http://192.168.11.21:8080" # 第22行

设置开机启动&启动K8s相关服务:

1
2
3
4
5
6
[root@k8s-master ~]# systemctl enable kube-apiserver.service  
[root@k8s-master ~]# systemctl restart kube-apiserver.service
[root@k8s-master ~]# systemctl enable kube-controller-manager.service
[root@k8s-master ~]# systemctl restart kube-controller-manager.service
[root@k8s-master ~]# systemctl enable kube-scheduler.service
[root@k8s-master ~]# systemctl restart kube-scheduler.service

检查服务是否安装正常

1
2
3
4
5
[root@k8s-master ~]# kubectl get componentstatus                                                                                                       
NAME STATUS MESSAGE ERROR
etcd-0 Healthy {"health":"true"}
scheduler Healthy ok
controller-manager Healthy ok

为Node节点安装Kubernetes

在k8s-node1& k8s-node2节点分别执行以下命令:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
yum install kubernetes-node.x86_64 -y  # 安装k8s

vim /etc/kubernetes/config :set nu # 修改kubernetes配置文件
KUBE_MASTER="--master=http://192.168.11.21:8080"

vim /etc/kubernetes/kubelet # 修改kubernetes配置文件

# 第5行 将默认值修改为 0.0.0.0
KUBELET_ADDRESS="--address=0.0.0.0"
# 第8行 打开注释
KUBELET_PORT="--port=10250"
# 第11行 修改默认值为node节点的Ip
KUBELET_HOSTNAME="--hostname-override=10.0.0.12"
# 第14行 修改默认值为Master节点的IP
KUBELET_API_SERVER="--api-servers=http://10.0.0.11:8080"

修改完成配置之后,分别重启相关服务:

1
2
3
4
systemctl enable kubelet.service
systemctl restart kubelet.service
systemctl enable kube-proxy.service
systemctl restart kube-proxy.service

为所有节点配置Flannel网络

在所有节点上进行安装Flannel ,然后修改其配置文件:

1
2
yum install flannel -y
sed -i 's#http://127.0.0.1:2379#http://192.168.11.21:2379#g'

Master节点:

1
2
3
4
5
6
7
8
9
10
##master节点:
etcdctl mk /atomic.io/network/config '{ "Network": "172.18.0.0/16" }'
yum install docker -y
systemctl enable flanneld.service
systemctl restart flanneld.service
systemctl restart docker
systemctl enable docker
systemctl restart kube-apiserver.service
systemctl restart kube-controller-manager.service
systemctl restart kube-scheduler.service

Node节点:

1
2
3
4
5
6
7
8
9
10
11
systemctl enable flanneld.service 
systemctl restart flanneld.service
systemctl restart docker
systemctl restart kubelet.service
systemctl restart kube-proxy.service

vim /usr/lib/systemd/system/docker.service
#在[Service]区域下增加一行
ExecStartPost=/usr/sbin/iptables -P FORWARD ACCEPT
systemctl daemon-reload
systemctl restart docker

将Master节点配置为镜像仓库

1
2
3
4
5
6
7
8
9
10
11
vi /etc/docker/daemon.json
{
"registry-mirrors": ["https://registry.docker-cn.com"],
"insecure-registries": ["10.0.0.11:5000"]
}

systemctl restart docker

#master节点
docker run -d -p 5000:5000 --restart=always --name registry -v /opt/myregistry:/var/lib/registry registry

至此一个简单的K8s集群就搭建完毕了。

环境测试

在Master节点检查集群服务是否正常:

1
2
3
4
[root@k8s-master ~]# kubectl get nodes                      
NAME STATUS AGE
192.168.11.22 Ready 29s
192.168.11.23 Ready 27s

如果出现如上内容说明集群各节点正常运行。

Oracle排查全表扫描的语句

1
2
3
4
5
SELECT *
FROM V$SQL_PLAN V
WHERE V.OPERATION = 'TABLE ACCESS'
AND V.OPTIONS = 'FULL'
AND V.OBJECT_OWNER='SYSTEM';

依据SQL ID找出相对应的 SQL TEXT

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33

SELECT SQL_TEXT,
SQL_FULLTEXT,
SQL_ID,
LOADS,
FIRST_LOAD_TIME,
PLSQL_EXEC_TIME,
JAVA_EXEC_TIME,
ROWS_PROCESSED,
COMMAND_TYPE,
PARSING_USER_ID,
PARSING_SCHEMA_ID,
PARSING_SCHEMA_NAME,
KEPT_VERSIONS,
ADDRESS,
SERVICE,
MODULE,
MODULE_HASH,
ACTION,
CPU_TIME,
ELAPSED_TIME,
OUTLINE_SID,
CHILD_ADDRESS,
SQLTYPE,
REMOTE,
OBJECT_STATUS,
LITERAL_HASH_VALUE,
LAST_LOAD_TIME,
PROGRAM_ID,
PROGRAM_LINE#,
LAST_ACTIVE_TIME
FROM V$SQL
WHERE SQL_ID = '9b0pykv6ww3jq';

1
SELECT  *  FROM V$SQL WHERE SQL_ID = '9b0pykv6ww3jq';

表访问的几种方式:(非全部)

  • TABLE ACCESS FULL(全表扫描)
  • TABLE ACCESS BY ROWID(通过ROWID的表存取)
  • TABLE ACCESS BY INDEX SCAN(索引扫描)

索引扫描又分五种:

  • INDEX UNIQUE SCAN(索引唯一扫描)
  • INDEX RANGE SCAN(索引范围扫描)
  • INDEX FULL SCAN(索引全扫描)
  • INDEX FAST FULL SCAN(索引快速扫描)
  • INDEX SKIP SCAN(索引跳跃扫描)

参考:

https://www.cnblogs.com/ShaYeBlog/p/10863118.html

https://www.cnblogs.com/gered/p/8568085.html

问题简述

数据库中用来存储客户信息表的主键字段类型 **VARCHAR2(4)**。某天,值累计到9999,这时候系统出现异常 无法正常插入数据,综合其他模块来看,决定使用存储函数来解决主键字段不够用的情况,即使用子母结合数字的方式来生成主键序列,以下是具体的实现方式。

核心代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
create FUNCTION FN_CTPK_INCREASE
/********************************************************************
[Function名称]: FN_CTPK_INCREASE
[目 的]: 解决表字段不够用的问题
[备 注]:
[参 数]:
# INPUT:

# OUTPUT:
1. RTN_FIELD 返回处理好的PK值

[使用示例]: SELECT FN_CTPK_INCREASE() FROM DUAL;

[VERSION ]:
|----------|-----------|----------------|-------------------|
|版本 |日期 |制作/修改者 |说明 |
|----------|-----------|----------------|-------------------|
|1.0 |2019-11-09 |柒索 | |
|----------|-----------|----------------|-------------------|
********************************************************************/
RETURN VARCHAR2 AS
RTN_FIELD VARCHAR2(30); /*最终返回值*/
FILED_VAL VARCHAR2(4); /*表中主键的最大值*/
FIELD_CNT NUMBER; /*统计数量*/
FILED_VAL1 VARCHAR2(1); /*拆分最大值 第一位*/
FILED_VAL2 VARCHAR2(1); /*拆分最大值 第二位*/
FILED_VAL3 VARCHAR2(1); /*拆分最大值 第三位*/
FILED_VAL4 VARCHAR2(1); /*拆分最大值 第四位*/
BEGIN
/*统计列中包含字母的值*/
SELECT COUNT(1)
INTO FIELD_CNT
FROM CITY
WHERE REGEXP_LIKE(CID, '([A-Z])');

/*如果统计到列中包含字母的主键的值为0时 将返回值RTN_FIELD设置为A000*/
IF FIELD_CNT = 0 THEN
RTN_FIELD := 'A000';
ELSE
/*获取CITY表中的最大值*/
SELECT NVL(MAX(CID), '0000')
INTO FILED_VAL
FROM CITY
WHERE REGEXP_LIKE(CID, '([A-Z])');

/*将拿到的值进行拆分*/
SELECT SUBSTR(FILED_VAL, 1, 1),
SUBSTR(FILED_VAL, 2, 1),
SUBSTR(FILED_VAL, 3, 1),
SUBSTR(FILED_VAL, 4, 1)
INTO FILED_VAL1, FILED_VAL2, FILED_VAL3, FILED_VAL4
FROM DUAL;

/*
ASCII编码中0、9、A、Z分别对应的数字如下:
ASCII('0') = 48
ASCII('9') = 57
ASCII('A') = 65
ASCII('Z') = 90
*/

IF TO_NUMBER(ASCII(FILED_VAL4)) = 90 THEN
FILED_VAL4 := '0';
IF TO_NUMBER(ASCII(FILED_VAL3)) = 90 THEN
FILED_VAL3 := '0';
IF TO_NUMBER(ASCII(FILED_VAL2)) = 90 THEN
FILED_VAL2 := '0';
IF TO_NUMBER(ASCII(FILED_VAL1)) = 57 THEN
FILED_VAL1 := 'A';
ELSE
FILED_VAL1 := CHR(TO_NUMBER(ASCII(FILED_VAL1)) + 1);
END IF;
ELSE
IF TO_NUMBER(ASCII(FILED_VAL2)) = 57 THEN
FILED_VAL2 := 'A';
ELSE
FILED_VAL2 := CHR(TO_NUMBER(ASCII(FILED_VAL2)) + 1);
END IF;
END IF;
ELSE
IF TO_NUMBER(ASCII(FILED_VAL3)) = 57 THEN
FILED_VAL3 := 'A';
ELSE
FILED_VAL3 := CHR(TO_NUMBER(ASCII(FILED_VAL3)) + 1);
END IF;
END IF;
ELSE
IF TO_NUMBER(ASCII(FILED_VAL4)) = 57 THEN
FILED_VAL4 := 'A';
ELSE
FILED_VAL4 := CHR(TO_NUMBER(ASCII(FILED_VAL4)) + 1);
END IF;
END IF;
/*拼接处理结果 RETURN*/
RTN_FIELD := FILED_VAL1||FILED_VAL2||FILED_VAL3||FILED_VAL4;
END IF;
/*DBMS_OUTPUT.PUT_LINE('RETURN-:' || RTN_FIELD);*/
RETURN RTN_FIELD;
END FN_CTPK_INCREASE;
/

测试调用

1
2
3
4
5
6
7
8
9
10
11
/* 测试: 循环插入数据 查看主键的变化*/
BEGIN
FOR i IN 1 .. 1000 LOOP
INSERT INTO SCOTT.CITY (CID, CNAME, CTYCODE, DISTRICT, INFO)
VALUES (FN_CTPK_INCREASE(),
'Shanghai',
'CHN',
'Shanghai',
'{"Population": 9696300}');
END LOOP;
END;

PS:原主键生成方式:

1
2
3

SELECT NVL((SELECT CID + 1 FROM CITY WHERE CID > ' ' AND ROWNUM = 1 ), '1000') FROM DUAL;

查看结果

1
2
3
SELECT * FROM CITY
WHERE ROWNUM < 50
ORDER BY CID;
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
1000	Boston       	USA  	Massachusetts	{"Population": 589141}
9999 Panchiao CHN Taipei {"Population": 523850}
A000 Shanghai CHN Shanghai {"Population": 9696300}
A001 Shanghai CHN Shanghai {"Population": 9696300}
A002 Shanghai CHN Shanghai {"Population": 9696300}
A003 Shanghai CHN Shanghai {"Population": 9696300}
A004 Shanghai CHN Shanghai {"Population": 9696300}
A005 Shanghai CHN Shanghai {"Population": 9696300}
A006 Shanghai CHN Shanghai {"Population": 9696300}
A007 Shanghai CHN Shanghai {"Population": 9696300}
A008 Shanghai CHN Shanghai {"Population": 9696300}
A009 Shanghai CHN Shanghai {"Population": 9696300}
A00A Shanghai CHN Shanghai {"Population": 9696300}
A00B Shanghai CHN Shanghai {"Population": 9696300}
A00C Shanghai CHN Shanghai {"Population": 9696300}
A00D Shanghai CHN Shanghai {"Population": 9696300}
A00E Shanghai CHN Shanghai {"Population": 9696300}
A00F Shanghai CHN Shanghai {"Population": 9696300}
A00G Shanghai CHN Shanghai {"Population": 9696300}
A00H Shanghai CHN Shanghai {"Population": 9696300}
A00I Shanghai CHN Shanghai {"Population": 9696300}
A00J Shanghai CHN Shanghai {"Population": 9696300}
A00K Shanghai CHN Shanghai {"Population": 9696300}
A00L Shanghai CHN Shanghai {"Population": 9696300}
A00M Shanghai CHN Shanghai {"Population": 9696300}
A00N Shanghai CHN Shanghai {"Population": 9696300}
A00O Shanghai CHN Shanghai {"Population": 9696300}
A00P Shanghai CHN Shanghai {"Population": 9696300}
A00Q Shanghai CHN Shanghai {"Population": 9696300}
A00R Shanghai CHN Shanghai {"Population": 9696300}
A00S Shanghai CHN Shanghai {"Population": 9696300}
A00T Shanghai CHN Shanghai {"Population": 9696300}
A00U Shanghai CHN Shanghai {"Population": 9696300}
A00V Shanghai CHN Shanghai {"Population": 9696300}
A00W Shanghai CHN Shanghai {"Population": 9696300}
A00X Shanghai CHN Shanghai {"Population": 9696300}
A00Y Shanghai CHN Shanghai {"Population": 9696300}
A00Z Shanghai CHN Shanghai {"Population": 9696300}
A010 Shanghai CHN Shanghai {"Population": 9696300}
A011 Shanghai CHN Shanghai {"Population": 9696300}
A012 Shanghai CHN Shanghai {"Population": 9696300}
A013 Shanghai CHN Shanghai {"Population": 9696300}
A014 Shanghai CHN Shanghai {"Population": 9696300}
A015 Shanghai CHN Shanghai {"Population": 9696300}
A016 Shanghai CHN Shanghai {"Population": 9696300}
A017 Shanghai CHN Shanghai {"Population": 9696300}
A018 Shanghai CHN Shanghai {"Population": 9696300}
A019 Shanghai CHN Shanghai {"Population": 9696300}
A01A Shanghai CHN Shanghai {"Population": 9696300}

插入示例

1
2
3
4
5
6
INSERT INTO SCOTT.CITY (CID, CNAME, CTYCODE, DISTRICT, INFO)
VALUES (FN_CTPK_INCREASE(),
'Shanghai',
'CHN',
'Shanghai',
'{"Population": 9696300}');

Done.

下载安装包

1
[vagrant@dk ~]$ wget http://mirrors.ustc.edu.cn/golang/go1.13.linux-amd64.tar.gz

使用USTC 中科大开源镜像站,速度更快一些。

解压&配置

1
2
3
4
5
6
7
8
9
10
11
12
[vagrant@dk ~]$ sudo mkdir /opt/gowork  # 工作目录
[vagrant@dk ~]$ sudo tar -xvf go1.13.linux-amd64.tar.gz -C /opt/
[vagrant@dk ~]$ mkdir /opt/gowork
[vagrant@dk ~]$ sudo vim /etc/profile # 配置GOPATH&GOROOT

export GOPATH=/opt/gowork
export GOROOT=/opt/go
export PATH=$PATH:$GOROOT/bin:$GOPATH/bin

[vagrant@dk ~]$ source /etc/profile # 刷新配置
[vagrant@dk ~]$ go version # 查看版本
go version go1.13 linux/amd64

Hello World:

1
2
3
[vagrant@dk ~]$ cd $GOPATH             # 进入到工作目录
[vagrant@dk gowork]$ sudo touch main.go
[vagrant@dk gowork]$ sudo vim main.go

main.go:

1
2
3
4
5
6
7
8
9
package main

import (
"fmt"
)

func main(){
fmt.Println("Hello GoLang~")
}
1
2
3
[vagrant@dk gowork]$ go run main.go   # 执行main.go
Hello GoLang~

Done.

环境说明

VirtualBox6.0、Vagrant2.2.3、CentOS7.6 、Dodkcer 18.09.7 、Oracle11G、

Docker Image:docker pull registry.cn-hangzhou.aliyuncs.com/helowin/oracle_11g

PS:数据库运行VirtualBox虚拟机中的CentOS系统上的Docker容器中,使用Scott用户

游标简介

游标是Oracle执行SQL与的内存区域。在数据库编程中,游标是内部数据结构,能够处理SQL查询结果。

游标是相对于上下文区域的句柄或者指针。借助于游标PL/SQL程序可以控制上下文区域,以及当语句执行时所发生的事情。

游标有两种类型,分别为隐式游标和显式游标:

  • 隐式游标:每当SQL语句执行时,Oracle会自动声明一个隐式游标。用户不会感觉到这一点,并且不能控制或者处理隐式游标的信息。
  • 显式游标:对于返回多行数据的任何查询,都可以为之定义显式游标,定义好的游标可以处理返回的每行数据。

游标属性

在处理游标时,可能需要确定游标的状态。 以下是可以使用的游标属性列表。

属性 返回值 释义
%ISOPEN Boolean 游标处于打开状态返回TRUE
%FOUND Boolean 执行成功,则返回TRUE;、没有执行被返回,则返回FALSE
%NOTFOUND Boolean 执行了成功的FETCH,则返回FALSE、没有执行被返回,则返回TRUE
%ROWCOUNT Number 返回从游标中所检索的记录数

PS: 如果声明了游标,但不打开,则返回INVALID_CURSOR,或者游标已关闭。

隐式游标

隐式游标会自动的与每个DML语句(UPDATE、DELETE、INSERT)建立关联,所有的UPDATE、DELETE语句都有标识被当前操作所影响数据行集合的游标。
隐式游标被用户处理INSERT、UPDATE、DELETE和SELETE INTO语句,在处理隐式游标的过程中,Oracle会自动执行OPEN、FETCH和CLOSE的操作。

  • INSERT 使用游标:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    set serveroutput on;
    begin
    INSERT INTO SCOTT.EMP (EMPNO, ENAME, JOB, MGR, HIREDATE, SAL, COMM, DEPTNO)
    VALUES (7986, 'Nathan', 'SYSDBA', 7698,
    TO_DATE('2019-09-04 00:00:00', 'YYYY-MM-DD HH24:MI:SS'),
    18621.00, null, 20);
    DBMS_OUTPUT.PUT_LINE('INSERT:EMP=>受影响的行数是'||SQL%ROWCOUNT||'行');
    end;

    --执行结果:
    [2019-09-04 11:38:57] completed in 24 ms
    [2019-09-04 11:38:57] INSERT:EMP=>受影响的行数是1行
  • SELECT INTO使用游标:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    set serveroutput on;
    declare
    ename varchar2(20);
    sal number;
    begin
    select emp.ename, emp.sal
    into ename , sal
    from emp where emp.empno = 7986;
    DBMS_OUTPUT.PUT_LINE('SELECT:EMP=>'||ename||'的薪水是'||sal);
    exception
    when NO_DATA_FOUND then
    DBMS_OUTPUT.PUT_LINE('SELECT:EMP=>没有找到数据!');
    end;

    -- 执行结果:
    [2019-09-04 11:39:54] completed in 6 ms
    [2019-09-04 11:39:54] SELECT:EMP=>Nathan的薪水是18621
  • UPDATE使用游标:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    set serveroutput on;
    begin
    update emp set emp.sal = 8000 where emp.empno = 7986;
    DBMS_OUTPUT.PUT_LINE('UPDATE:EMP=>受影响的行数是'||SQL%ROWCOUNT||'行');
    end;

    -- 执行结果:
    [2019-09-04 11:40:28] completed in 168 ms
    [2019-09-04 11:40:28] UPDATE:EMP=>受影响的行数是1行
  • DELETE使用游标:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    set serveroutput on;
    begin
    delete from emp where emp.empno = 7986;
    DBMS_OUTPUT.PUT_LINE('DELETE:EMP=>受影响的行数是'||SQL%ROWCOUNT||'行');
    end;

    --执行结果:
    [2019-09-04 11:41:48] completed in 10 ms
    [2019-09-04 11:41:48] DELETE:EMP=>受影响的行数是1行

显式游标

相较于隐式游标,显式游标的好处是可以对程序进行更多的编程控制,隐式游标的效率没有显式游标的效率高,更难以捕获异常。显式游标的使用分为以下四步:

  1. 声明游标:在内存中建立游标的初始化环境
  2. 打开游标:打开已经声明好的游标,分配内存
  3. 检索游标:通过已经声明和打开的游标来检索数据
  4. 关闭游标:关闭,释放内存。
  • 使用游标查询emp表中的员工名称以及薪水:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40

-- 开启输出
set serveroutput on;

-- 游标的
declare
-- 声明游标
cursor cur is select emp.ENAME,emp.SAL from emp;
ename emp.ename%type;
sal emp.sal%type;
begin
-- 打开游标
open cur;
loop
-- 检索数据
fetch cur into ename,sal;
-- 当游标中没有数据的时候退出
exit when cur%notfound;
DBMS_OUTPUT.PUT_LINE(ename|| '的薪水是'|| sal);
end loop;
-- 关闭游标
close cur;
end;

-- 执行结果:
[2019-09-04 09:01:55] completed in 5 ms
[2019-09-04 09:01:55] SMITH的薪水是800
[2019-09-04 09:01:55] ALLEN的薪水是1600
[2019-09-04 09:01:55] WARD的薪水是1250
[2019-09-04 09:01:55] JONES的薪水是2975
[2019-09-04 09:01:55] MARTIN的薪水是1250
[2019-09-04 09:01:55] BLAKE的薪水是2850
[2019-09-04 09:01:55] CLARK的薪水是2450
[2019-09-04 09:01:55] SCOTT的薪水是3000
[2019-09-04 09:01:55] KING的薪水是5000
[2019-09-04 09:01:55] TURNER的薪水是1500
[2019-09-04 09:01:55] ADAMS的薪水是1100
[2019-09-04 09:01:55] JAMES的薪水是950
[2019-09-04 09:01:55] FORD的薪水是3000
[2019-09-04 09:01:55] MILLER的薪水是1300

Done.