在pl/sql中调用shell命令的4种方法
来源:互联网 发布:手机画线软件 编辑:程序博客网 时间:2024/05/22 06:16
本来想是一个很简单的操作,可惜Oracle没有提供简单的一个命令(也许我不知道吧),只好进行一些复杂点的操作了。一般有三种方式实现:
1. 利用DBMS_PIPE包并创建OS上运行的守护进程;
2. 调用c程序来实现
3. 利用java的getRuntime().exec;
4. 使用oracle的EXECUTABLE jobs功能。
利用DBMS_PIPE包并创建OS上运行的守护进程
觉得这种方式复杂,还要用到pro*c,没试。(
利用java的getRuntime().exec
这种好点,java用的还是蛮多的。
1)写个简单的java程序 ExecuteCmd.java
import java.lang.Runtime;
import java.lang.Process;
import java.io.IOException;
import java.lang.InterruptedException;
class ExecuteCmd {
public static void main(String args[]) {
System.out.println("Start executing");
try {
/* Execute the command using the Runtime object and get the
Process which controls this command */
Process p = Runtime.getRuntime().exec(args[0]);
/* Use the following code to wait for the process to finish
and check the return code from the process */
try {
p.waitFor();
/* Handle exceptions for waitFor() */
} catch (InterruptedException intexc) {
System.out.println("Interrupted Exception on waitFor: " + intexc.getMessage());
}
System.out.println("Return code from process: "+ p.exitValue());
System.out.println("Done executing");
/* Handle the exceptions for exec() */
} catch (IOException e) {
System.out.println("IO Exception from exec: " + e.getMessage());
e.printStackTrace();
}
}
}
2)编译生成 ExecuteCmd.class
javac ExecuteCmd.java
3)加载到oracle中
$ loadjava -user system/manager ExecuteCmd.class
4)生成java存储过程
CREATE OR REPLACE PROCEDURE executecmd (S1 VARCHAR2)
AS LANGUAGE JAVA
name 'ExecuteCmd.main(java.lang.String[])';
/
测试:
SQL> set serveroutput on
SQL> call dbms_java.set_output(2000);
SQL> EXEC executecmd('/bin/touch /home/oracle/a.txt');
Start executing
Return code from process: 0
Done executing
PL/SQL procedure successfully completed.
SQL> host
$ ls /home/oracle
a.txt
执行成功了,但还是有些问题,比如参数中不能使用环境变量 EXEC executecmd('/bin/touch $HOME/a.txt')执行不行,绝对路径和相对路径的问题,还要给执行用户(这里是system用户)授予相应的权限等等。所以我觉得还是应该先把要做的事写一个shell可执行脚本,然后再如上调用,这样会省去一些麻烦。
使用C程序调用
有时,我们会发现有些功能通过PL/SQL完成会很麻烦,而通过C/C++语言编程则会容易很多。因此,oracle提供了在PL/SQL程序里直接调用外部函数(包括C函数或Java方法)的功能,从而扩展了PL/SQL的程序功能。调用外部函数的过程如下图所示。
调用外部函数的过程
从上图可以看出,调用外部函数的过程包括:
<!--[if !supportLists]-->1) <!--[endif]-->用户进程执行PL/SQL程序。
<!--[if !supportLists]-->2) <!--[endif]-->在执行的PL/SQL程序过程中,调用了一个C/C++语言写的函数:c_func。这里需要借助别名库(Alias Library)。别名库是数据库里的一个对象,用来描述一个外部函数所在的动态链接库的路径和名称。通过别名库,从而可以知道被调用的外部函数在哪个文件里。
<!--[if !supportLists]-->3) <!--[endif]-->PL/SQL将对外部函数的调用请求发送给监听器。
<!--[if !supportLists]-->4) <!--[endif]-->监听器生成一个extproc进程,该进程专门用来处理对外部函数的调用。每个session都会生成一个属于该session的extproc进程,并且在整个session生命周期里,extproc进程会一直存在。
<!--[if !supportLists]-->5) <!--[endif]-->Extproc进程负责将别名库所指定的动态链接库文件加载到内存。
<!--[if !supportLists]-->6) <!--[endif]-->Extproc进程执行指定的外部函数,并将结果返回给服务器进程,进而返回给用户进程。
需要对监听器进行配置,从而启动extproc进程,配置方式如前面的图11-3所示。其中(ADDRESS = (PROTOCOL = IPC)(KEY = EXTPROC0))说明监听extproc进程请求的地址;而SID_DESC部分则说明extproc进程的连接信息。
然后我们还要配置tnsnames.ora文件,注意,该文件也必须位于数据库服务器端。我们需要添加如下图的内容。
配置tnsnames.ora
配置完毕以后,可以尝试tnsping连接字符串名称,如果成功,则说明监听没有问题。
[oracle@book admin]$ tnsping EXTPROC_CONNECTION_DATA
接下来,我们创建一个C语言编写的函数,如下所示。该函数完成的功能非常简单,计算传入参数的15%,并作为税额返回给调用者。
[oracle@book ~]$ vi calc_tax.c
calc_tax(n)
int n;
{
int tax;
tax=(n*15)/100;
return (tax);
}
将calc_tax.c文件编译成动态链接库,并将生成的库文件拷贝到$ORACLE_HOME/bin目录下:
[oracle@book ~]$ cc -shared -o calc_tax.so calc_tax.c
[oracle@book ~]$ cp calc_tax.so $ORACLE_HOME/bin
然后,我们创建一个别名库,用来说明将要调用的C函数所在的库文件,并将使用c_code别名库的权限赋给HR用户:
SQL> connect / as sysdba
SQL> create or replace library c_code as '$ORACLE_HOME/bin/calc_tax.so';
2 /
SQL> grant execute on c_code to hr;
要使用这个calc_tax函数,还必须在数据库里创建一个调用声明。如下所示:
SQL> connect hr/hr
SQL> create or replace function call_c
2 (x binary_integer)
3 return binary_integer
4 as language C
5 library sys.c_code
6 name "calc_tax";
7 /
在调用声明里定义了calc_tax函数的传入传出参数、所在的别名库名称(library sys.c_code部分)、以及在动态链接库中的函数名(name "calc_tax")等。
现在,我们就可以通过调用call_c,进而调用calc_tax函数了。如下所示:
SQL> set serveroutput on
SQL> var v_salary number;
SQL> var v_tax number;
SQL> exec :v_salary := 10000;
SQL> exec :v_tax := call_c(:v_salary);
SQL> print v_tax;
V_TAX
-----------------
1500
注:以上内容摘自《Oracle数据库核心技术与实务详解-教你如何成为10g OCP》一书
使用oracle的EXECUTABLE jobs功能
对DBMS_SCHEDULER没什么研究,论坛上有个例子,但我没试通,有时间再研究一下,应该也可以。
exec DBMS_SCHEDULER.CREATE_JOB
(job_name=>'test13',job_type=>'EXECUTABLE',job_action=>'/tmp/test1.sh');
exec DBMS_SCHEDULER.RUN_JOB(job_name=>'test13');
- 在pl/sql中调用shell命令的4种方法
- 在pl/sql中调用shell命令的4种方法
- 在pl/sql中调用shell命令
- 在PL/SQL中调用Java方法
- Python调用shell命令的几种方法(在新进程中执行shell命令)
- 在C语言中调用shell命令的实现方法
- 在PL/SQL Developer中初始化的几种方法
- 在PL/SQL Developer中初始化的几种方法
- PL/SQL小技巧一个:在子类中怎么调用父类被重载的方法
- PL/SQL小技巧一个:在子类中怎么调用父类被重载的方法
- 在.NET中调用PL/SQL返回游标的取得
- 在java中调用pl/sql编写的存储过程
- [VB.NET]请问我如何在vb.net中调用pl/sql包中已经写好的方法?
- 六种调用shell命令的方法
- [oracle] 在pl /sql中批量录入测试数据的方法!!!
- 解析如何在C语言中调用shell命令的实现方法
- 在命令窗口中编写pl/sql编写函数,并执行调用
- 在Oracle的pl/sql developer中修改表的2种方法
- 这几天有些闲了,但是心却紧了
- www.xml-sitemaps.com 生成站点地图
- decimal数据小数点前不能显示的问题
- 关于meanshift的一些介绍
- SQL 游标学习
- 在pl/sql中调用shell命令的4种方法
- c# 如何求出符合条件的总条数
- C#2.0锐利体验_匿名方法,迭代器
- 子非鱼,安知鱼之乐
- JavaScript 用DIV模拟弹出窗口并跟随窗体滚动
- Socket send函数和recv函数详解
- 常用的Webservice
- 小议大学生活
- 引擎控制命令脚本