在pl/sql中调用shell命令的4种方法

 

本来想是一个很简单的操作,可惜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

      从返回结果可以看到,我们成功调用了C函数:calc_tax。

注:以上内容摘自《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');
  • 1
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
要在 PL/SQL 调用 Java 类或方法,需要按照以下步骤进行操作: 1. 使用 CREATE OR REPLACE JAVA SOURCE 创建 Java 源代码,然后使用 loadjava 工具将其加载到数据库。 2. 创建 Java 存储过程或函数并将其编译为 class 文件。 3. 在 PL/SQL 创建一个包含外部过程和函数的包,并将其与 Java 存储过程或函数进行映射。 4. 在 PL/SQL 调用的外部过程和函数,以调用 Java 存储过程或函数。 下面是一个简单的示例代码,演示如何在 PL/SQL 调用 Java 存储过程: 1. 首先,创建一个名为 TestJava 的 Java 类,该类包含一个名为 add 的方法,该方法接受两个整数参数并返回它们的和。 CREATE OR REPLACE JAVA SOURCE NAMED "TestJava" AS public class TestJava { public static int add(int a, int b) { return a + b; } }; / 2. 接下来,创建一个名为 addNumbers 的 Java 存储过程,该过程调用 TestJava 类的 add 方法,并将结果存储在一个 OUT 参数。 CREATE OR REPLACE AND RESOLVE JAVA SOURCE NAMED "AddNumbers" AS import java.sql.*; public class AddNumbers { public static void add(int a, int b, int[] result) throws SQLException { result[0] = TestJava.add(a, b); } }; / 3. 然后,创建一个名为 MyPackage 的 PL/SQL 包,该包包含一个名为 add 的过程,该过程调用 addNumbers 存储过程,并将结果返回给调用者。 CREATE OR REPLACE PACKAGE MyPackage AS PROCEDURE add(a IN NUMBER, b IN NUMBER, result OUT NUMBER); END; / CREATE OR REPLACE PACKAGE BODY MyPackage AS PROCEDURE add(a IN NUMBER, b IN NUMBER, result OUT NUMBER) AS LANGUAGE JAVA NAME 'AddNumbers.add(int, int, int[])'; END; / 4. 最后,可以在 PL/SQL 调用 MyPackage 包的 add 过程,以调用 Java 存储过程,并将结果返回给调用者。 DECLARE result NUMBER; BEGIN MyPackage.add(1, 2, result); DBMS_OUTPUT.PUT_LINE(result); END; / 这就是在 PL/SQL 调用 Java 存储过程的基本过程。注意,为了使 PL/SQL 能够调用 Java 存储过程,需要在数据库安装 JDK,并将相关的 JAR 文件加载到数据库

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值