shell mysql并发_shell脚本中的多进程并发处理
在前面的篇章里面,我们已经介绍了常见的各种shell命令操作。然而,在实际工作中,我们经常会遇到多种任务需要在一定时间内都解决掉。如果这些任务是相互独立的,即不存在先后执行关系,那么我们完全可以让它们同时处理,这样可以大大缩短任务的执行时间,提高我们的工作效率。在其他高级语言中,比如C++或者java,我们通常会采用多线程或者多进程来处理。同样,利用shell脚本我们也能实现多任务并发处理。这一节将介绍如何利用shell脚本进行多任务并发处理。
1.基本原理
关于如何创建多个进程同时运行,在前面的章节我们已有介绍,可以通过协程或者&操作实现。在这里主要讲如何进行控制,即如何按照预期目标让这些多进程有序进行。
要控制创建的进程按照预期目标进行操作,必然涉及到进程间的通信。关于进程间通信的技术有很多,比如临界区、管道、文件、信号、信号量、套接字等等。而对于多进程并发操作,我们将采用管道技术进行控制。
在类Unix操作系统中,管道是一个由标准输入输出链接起来的进程集合,因此,每一个进程的输出将直接作为下一个进程的输入。本质上讲,管道是一种特殊的文件。
管道有一个特点,如果管道中没有数据,那么取管道数据的操作就会滞留,直到管道内进入数据,然后读出后才会终止这一操作;同理,写入管道的操作如果没有读取管道的操作,这一动作就会滞留。
然而与之前介绍的管道命令“|”不同的是,这个管道需要创建者进行命名。为了区分它们,我们把前一种管道称为匿名管道,后一种管道称为命名管道。接下来,我们将详细比较这种管道的异同,以及为什么在多进程并发中需要采用命名管道。
1.1 匿名管道
在类Unix操作系统的命令行中,匿名管道使用ASCII中垂直线“|”作为匿名管道符,匿名管道的两端是两个普通的、匿名的、打开的文件描述符:一个只读端和一个只写端,这就让其它进程无法连接到该匿名管道。
例如:
cat file | cut -b 3
为了执行上面的指令,Shell创建了两个进程来分别执行cat和cut。值得注意的是,两个进程都连接到了管道上,这样写入进程cat就将其标准输出(文件描述符为fd 1)连接到了管道的写入端,读取进程cut就将其标准输入(文件描述符为fd 0)连接到了管道的读入端。实际上,这两个进程并不知道管道的存在,它们只是从标准文件描述符中读取数据和写入数据。shell必须要完成相关的工作。
1.2命名管道
命名管道也称FIFO,是First In First Out的缩写。从语义上来讲,FIFO其实与匿名管道类似,但值得注意:在文件系统中,FIFO拥有名称,并且是以设备特俗文件的形式存在的;
任何进程都可以通过FIFO共享数据;
除非FIFO两端同时有读与写的进程,否则FIFO的数据流通将会阻塞;
匿名管道是由shell自动创建的,存在于内核中;而FIFO则是由程序创建的(比如mkfifo命令),存在于文件系统中;
匿名管道是单向的字节流,而FIFO则是双向的字节流;
1.3多进程并发控制
在有了前面的基础知识之后,我们来讲如何使用命名管道进行多进程并发控制。
命名管道,从它的缩写我们可以看出它具有队列的性质,实际亦然。使用命名管道进行多进程并发控制的基本步骤为:创建一个命令管道
将命名管道绑定到一个特定的文件描述符
设置命名管道的大小。注意命名管道的大小,是通过写入记录的行数来决定的
依次读取命名管道,来创建运行新进程,执行多任务
四个步骤对应四个关键点,因此学习的时候需要牢牢记住。
2.具体实现
由于oracle数据库是目前最好的商用关系型数据库,在实际的工作中我们会经常用到。在关于数据库的操作,我们经常要做的就是数据的导入导出。这里以此为例,介绍如何使用shell多任务并发处理脚本进行oracle数据库的数据导入。
#! /bin/bash
source /etc/profile;
tempfifo=$$.fifo # $$表示当前执行文件的PID
cnt=$1 # 进程数目
data_path=$2 # 数据文件路径
ctl_path=$3 #控制文件路径
db_user=$4 #数据库用户名
db_passwd=$5 #数据库密码
#捕获Ctrl+C中断命令,则关闭文件描述符1000的读写,并正常退出
trap "exec 10>&-;exec 10
#创建一个管道文件,并与文件描述符10绑定
mkfifo $tempfifo
exec 10<>$tempfifo
rm -rf $tempfifo
#对文件描述符10进行写入操作。通过循环写入cnt个空行,这个cnt就是我们要定义的后台并发的线程数。
for ((i=1; i<=$cnt; i++))
do
echo >&10
done
for file in ` ls $data_path `
do
#读取命名管道内容,并创建进程在后台运行
read -u10
{
#导入数据文件到oracle数据库,具体不详细写明,大家可以根据需要结合后面的内容自己实现
obcp $file $db_user $db_passwd $data_path $ctl_path
#写入空行,保持命名管道的容量不变,不然会阻塞
echo >&10
} &
done
#等待子进程都退出,然后关闭文件描述符10再退出
wait
echo "done"
exec 10>&-
exec 10
exit 0
3.oracle数据库的建表与导数相关操作
3.1 oracle数据库的连接
sqlplus user/passwd@ip:port/dbname
3.2 清空已有的表
例如:删除当前用户下的所有表的存储过程
create or replace PROCEDURE pro_dropalltables IS
BEGIN
declare cursor cur_tables is (select table_name from USER_TABLES);
begin
for v_table in cur_tables
loop
DBMS_OUTPUT.PUT_LINE('grant all on ' || v_table.table_name || ' to public ');
execute immediate 'drop table ' || v_table.table_name || ' cascade constraints purge ';
end loop;
end;
END pro_dropalltables ;
3.3 建立建表辅助存储过程
例如:删除表dropifexits.sql
create or replace PROCEDURE pro_dropifexits(p_table in varchar2)
AS
BEGIN
select count(*) into v_count from from USER_TABLES where table_name=upper(p_table ))
IF v_count>0 then
DBMS_OUTPUT.PUT_LINE('drop table' || p_table);
execute immediate 'drop table' || p_table ;
end IF;
END pro_dropifexits;
3.4 建表
exec pro_dropifexits('xxx');
create table tab_xxx(
xx char(10),
...
...
);
partition by list(xxx)
(
partition partiton_xx values('xxxxxx');
);
grant all on tab_xxx to dbuser;
3.5 添加、删除分区
例如:添加分区
create or replace PROCEDURE pro_addpartition(p_centre_id in varchar2,tablespace_var in varchar2,partition_var in varchar2)
AS
BEGIN
declare cursor cur_tables is select table_name from USER_PART_TABLES where table_name in (select table_name from USER_TABLES);
begin
for v_table in cur_tables
loop
DBMS_OUTPUT.PUT_LINE('grant all on ' || v_table.table_name || ' to public ');
execute immediate 'alter table' || v_table.table_name || ' add partition' || partition_var || 'values( ' || p_centre_id || ') tablespace' || tablespace_var ;
end loop;
end;
END pro_addpartition ;
例如:删除分区
create or replace PROCEDURE pro_addpartition(p_centre_id in varchar2,tablespace_var in varchar2,partition_var in varchar2) is v_count number(10);
BEGIN
declare cursor cur_tables is select table_name from USER_PART_TABLES where table_name in (select table_name from USER_TABLES);
begin
for v_table in cur_tables
loop
select count(*) into v_count from user_tab_partitions where TABLE_NAME=v_table.table_name in (select table_name from USER_TABLES)
IF v_count>0 then
DBMS_OUTPUT.PUT_LINE('grant all on ' || v_table.table_name || ' to public ');
execute immediate 'alter table' || v_table.table_name || ' drop partition' || partition_var ;
end IF;
end loop;
end;
END pro_addpartition ;
3.6 授权
例如:PRO_GRANTSCRIPT .sql
create or replace PROCEDURE PRO_GRANTSCRIPT IS
BEGIN
declare cursor cur_tables is (select table_name from USER_TABLES);
begin
for v_table in cur_tables
loop
DBMS_OUTPUT.PUT_LINE('grant all on ' || v_table.table_name || ' to public ');
execute immediate 'grant all on ' || v_table.table_name || ' to public ';
end loop;
end;
END PRO_GRANTSCRIPT ;
3.7 导数
数据格式:以"|!"作为属性分隔符,"!@!"作为元组分隔符
sqlldr命令格式
sqlldr infile='xxx' ctrl='/path/xx.ctrl' bad='/path/xx.bad' log='/path/xx.log' errors=1000
ctrl格式:
LOAD DATA
INFILE '/home/wan/xx.txt' "str X'0A214021'"
INTO TABLE tab_xx
insert(append)
fields terminated by '|!'
trailing nullcols
(
xx char(10),
...
...
)
另一种解决方式是将sqlldr写成一个执行命令,然后将ctrl文件批量化,最后就可以批量执行导数功能。
3.8 exp和imp导出、导入数据库备份
exp信息:
exp user/passwd@ip:port file=xxx/xxx.dmp log=xxx/xxx.log
imp信息:
imp user/passwd@ip:port file=xxx/xxx.dmp log=xxx/xxx.log full=y ignore=y
3.9 使用spool将执行结果写入文件
例如:查找所有的表名
set heading off;
set feedback off;
set trimspool on;
set colsep '|';
set wrap on;
spool /home/wan/file/test.txt
select table_name from USER_TABLES;
spool off;
shell mysql并发_shell脚本中的多进程并发处理相关推荐
- shell取mysql字段_shell 脚本中获取mysql多个字段的值
从mysql中查询出的结果为:mysql -Ne "SELECT ip,port FROM op.host WHERE os='linux' and type='支持'" +--- ...
- shell如何解决mysql交互式_shell脚本与mysql交互方法汇总
有大侠知道其他方法的,还请不吝赐教,在此谢过:) shell脚本导入数据文件到mysql内 当然是利用mysqlimport啦 示例脚本: #!/bin/sh # import test_table. ...
- shell脚本中数组的使用_Shell脚本中的数组
shell脚本中数组的使用 Knowing how to work with arrays in shell scripts will help you work with larger datase ...
- python logger设置信息取得_shell 脚本中如何获取 python logging 打印的信息?
在 shell 脚本中调用 python 的接口,但是 python API 是通过 python 的 logging 把相关信息打印到屏幕上的,不知道这种情况在 shell 中怎么获取这些 logg ...
- mysql 备份_shell脚本实现MySQL全量备份+异地备份
一. 知识储备 1) find命令,参考:Linux find 命令 2) MySQL导出数据库语法: mysqldump -u用户名 -p密码 数据库名 > 数据库名.sql 3) rsync ...
- 测试过程中用shell的地方_Shell脚本应用——条件测试操作
Shell脚本应用--条件测试操作 前言:在简单的shell脚本程序中,各条语句将按先后顺序依次执行,从而实现批处理的自动化过程,这就使得脚本过于机械化,不够"智能",难以处理更加 ...
- mysql中的shell脚本命令_shell脚本中mysql命令
展开全部 本文介绍 MySQL 8.0 shell 子模块 Util 的两个导入特性 importTable/import_table(JS和python 版本的命名差e68a84e8a2ad6261 ...
- shell mysql 取值_shell 脚本中获取mysql多个字段的值
从mysql中查询出的结果为:mysql -Ne "SELECT ip,port FROM op.host WHERE os='linux' and type='支持'" +--- ...
- mysql判断不等于空的脚本_Shell脚本中判断输入变量或者参数是否为空的方法
1.判断变量 复制代码代码如下: read -p "input a word :" word if [ ! -n "$word" ] ;then echo & ...
最新文章
- OpenCV+python:直方图的概念及绘制(Histogram)
- 泛型java 代码讲解_Java泛型详解
- monkey测试_安卓测试之monkey
- SpringSecurity系列(三) Spring Security 表单登录
- 判定三角形程序c语言,c语言判定三角形的各种类型——请大家指点
- 马克思主义基本原理习题册
- 解决刷新页面Vuex数据丢失问题
- Ubuntu 下查看图片
- esp32查询剩余内存_ESP32 Arduino教程:获取自由堆-esp文件
- 如何将鼠标和键盘连接到PlayStation 4
- 网站图片定位代码html5,CSS中背景图片的定位
- 辰信领创荣获“2016中国IT风云榜”两项大奖
- Java开发环境及其特点
- 你知道数据分析报告应该如何写吗?
- 虚拟机SSH免密登录
- ubuntu在目录下文件中搜索关键字
- PPT设计:PPT封面页9种设计布局/思维
- java 通联支付接口_allinpay 通联支付接口实例
- Java 模拟栈结构
- 计算机隐藏文件夹无法显示,无法显示隐藏文件怎么办 无法显示隐藏文件夹的解决方法...