设为首页 收藏本站
查看: 464|回复: 0

[经验分享] oracle 11g PL/SQL Programming学习十四

[复制链接]

尚未签到

发表于 2016-7-12 08:08:40 | 显示全部楼层 |阅读模式
----------------------------------------------------------------------------

-----------------PL/SQL学习笔记系列 By Cryking-----------------

------------------------转载请注明出处,谢谢!------------------------

  
  4.使用C共享库
oracle为外部存储构建了一个可扩展的架构.

它非常灵活地支持任何能被C调用的编程语言.
  定义C共享库(需要熟悉简单的C语言)

你将使用下面的C程序作为一个动态链接库(DLL)或共享库.

你需要安装一个C编译器来编译这个例子.

writestr1.c文件内容

/* Include standard IO. */
#include <stdio.h>
/* Declare a writestr function. */
void writestr(char *path, char *message){
/* Declare a FILE variable. */
FILE *file_name;
/* Open the file in write-only mode. */
file_name = fopen(path,"w");
/* Write to file the message received. */
fprintf(file_name,"%s\n",message);
/* Close the file. */
fclose(file_name);
}
  

--编译一个C共享库
[oracle@oracleserver oracle]$ vi writestr1.c
[oracle@oracleserver oracle]$ gcc -shared -o writestr1.so writestr1.c
[oracle@oracleserver oracle]$ ls *.so
writestr1.so
[oracle@oracleserver oracle]$ mkdir $ORACLE_HOME/customlib
[oracle@oracleserver oracle]$ mv writestr1.so /u01/app/oracle/product/11.2.0/dbhome_1/customlib/
  


你应当注意上面的C程序没有main函数,它只是作为一个DLL或共享库使用.

注意上面的编译方法(不要直接使用 gcc -o编译,否则会报缺失main函数).
  你需要在$ORACLE_HOME目录下创建一个自定义目录customlib.

你需要保证用户或组对customlib目录有读、写、执行的权限.
  定义和调用PL/SQL Library Wrapper

首先,定义PL/SQL库.

需要先在数据库定义外部库.(上面已经定义好,见listener.ora文件中的ENV参数.)

创建PL/SQL库语法原型为:

CREATE [OR REPLACE] LIBRARY <library_name> AS | IS

'<file_specification>'

AGENT '<agent_dblink>';

/
  示例:

23:46:18 SYS@ORCL> CREATE OR REPLACE LIBRARY library_write_string AS
23:47:50   2  '/u01/app/oracle/product/11.2.0/dbhome_1/customlib/writestr1.so';
23:47:52   3  /
Library created.
Elapsed: 00:00:00.23

  
  然后,建立PL/SQL library wrapper.

PL/SQL library wrapper主要用来定义一个数据库和外部存储的接口.

接口定义了PL/SQL参数和C数据类型的映射关系.

ORACLE提供额外的派生类型来支持OCI.
  在PL/SQL和C数据类型转换之间存在以下限制:

1.PL/SQL有NULL变量,但在C中没有对应的值.

当一个变量可能为NULL时,你需要使用另外一个变量(指示器变量)来通知该变量是否为NULL。

你使用OCI_IND_NULL和OCI_IND_NOTNULL来检查指示器变量是否为NULL.

2.当数据交换时,C和PL/SQL都需要知道string字符串的长度.

在处理二进制字符串时,你应当使用VSIZE来获得长度.

3.当extproc代理运行在一个不同的数据库时,CHARSETID和CHARSETFORM受制于全球化的复杂性.

创建一个C Library Wrapper存储过程的语法:

CREATE [OR REPLACE] PROCEDURE name [parameter_list]

AS EXTERNAL

LIBRARY_NAME library_name

NAME "<external_library_name>"

AGENT IN [parameter_list]

WITH CONTEXT

PARAMETER [parameter_list];
  下面的示例提出了一个比较独特的方法,使用隐式的SELF.
在PL/SQL,你不用去管理对象类型的SELF成员函数,因为它是隐式管理的.

如:


00:19:33 SYS@ORCL> CREATE OR REPLACE TYPE object_library_sample AS OBJECT(V NUMB
ER,member function get_tea_temperature return number);
00:21:06   2  /
Type created.
Elapsed: 00:00:00.45
--使用了上面创建好的library_write_string PL/SQL库
00:27:41 SYS@ORCL> CREATE OR REPLACE TYPE BODY object_library_sample AS
00:27:43   2    MEMBER FUNCTION get_tea_temperature RETURN NUMBER AS
00:27:43   3      LANGUAGE C NAME "tea_temp"
00:27:43   4      library library_write_string
00:27:43   5      WITH CONTEXT
00:27:43   6      PARAMETERS(CONTEXT,
00:27:43   7                 SELF   ,
00:27:43   8                 SELF    INDICATOR STRUCT,
00:27:43   9                 SELF    TDO,
00:27:43  10                 RETURN  INDICATOR);
00:27:43  11  END;
00:27:44  12  /
Type body created.
Elapsed: 00:00:00.19

  

创建PL/SQL外部存储.


00:27:45 SYS@ORCL> CREATE OR REPLACE PROCEDURE write_string(path VARCHAR2, message VARCHAR2) AS
01:00:25   2    EXTERNAL
01:00:25   3    LIBRARY library_write_string NAME "writestr"
01:00:25   4    PARAMETERS(path STRING, message STRING);
01:00:26   5  /
Procedure created.
Elapsed: 00:00:00.22

  
  在你学会如何定义和配置PL/SQL wrapper前,你应当知道如何建立网络连接(配置监听)、编译共享库、代理配置等.

完成这些后,现在你要知道如何使用它。

--调用外部存储write_string
01:00:28 SYS@ORCL> BEGIN
01:05:19   2  write_string('/tmp/file.txt','Hello World!');
01:05:19   3  END;
01:05:21   4  /
PL/SQL procedure successfully completed.
Elapsed: 00:00:00.29

  

  根据之前建立的C共享库,可以知道执行该外部存储之后,会建立对应文件,写入传入的内容.

验证:

[oracle@oracleserver oracle]$ more /tmp/file.txt
Hello World!
  
  使用外部存储时,有几点注意:
1.你不应使用全局变量,因为它们不是线程安全的.

2.你不应使用外部静态变量,因为它们不是线程安全的.

3.你只能在支持DLL或共享库的平台上使用外部存储.

4.你只能使用能被C调用的编程语言.

5.当你需要传递游标或记录类型到外部存储的时候,你必须使用对象来传递

6.你不能在PL/SQL wrapper的LIBRARY子句中使用DB_LINK.

7.最多传递128个参数.其中浮点类型或双精度类型算2个参数.


  5.使用JAVA共享库

oracle为外部存储构建了一个可扩展的架构.

它非常灵活地支持任何能被C调用的编程语言.

oracle直接支持java作为数据库的一部分.(除了oracle Express版)

java库不使用extproc,因为它们已经是本地oracle数据库的一部分了.

这简化了很多操作,但也带来了一些不便.(使用extproc代理和外部C库的时候)

java相比C,有几点优势:

1.JAVA理解SQL类型.它避免了乏味的数据类型映射.

2.JAVA是加载到oracle数据库里的.

这样避免了文件管理问题和监听ENV参数进程,因为它不需要使用extproc代理.

3.JAVA是本地线程安全的.

它不需要你去处理那些线程的细微差别,避免了静态变量.

4.JAVA不需要去管理内存地址.(也就是说JAVA没有指针)

java相比C,也有几点劣势:

1.JAVA使用了SGA中的JAVA池来管理进程.而C外部存储使用它们自己的内存空间.

换句话说就是C外部存储降低了SGA的内存消耗,而JAVA增加了SGA的负载.

2.JAVA的速度比不上C.

因为JAVA需要通过JVM来解释.

3.JAVA限制对文件的访问.这是为了保护数据库的完整性.

DBMS_JAVA包提供了一个方法来实现JAVA库程序的读写访问.

4.使用java库的PL/SQL wrapper函数在方法定义上有限制.

所有通过PL/SQL wrapper函数访问的JAVA class方法必须是静态的.

这样支持PL/SQL wrapper函数的java库就不是线程安全的了.
  下面来实现定义一个简单的java库.

首先,由于后面的程序包含了一个标准的I/O库,需要访问到外部物理文件.

所以需要先使用DBMS_JAVA.GRANT_PERMISSION来对相应目录进行授权.

01:51:44 SYS@ORCL>  BEGIN
01:52:16   2     DBMS_JAVA.GRANT_PERMISSION('SCOTT',
01:52:16   3                                'SYS:java.io.FilePermission',
01:52:16   4                                '/home/oracle/file.txt',
01:52:16   5                                'read');
01:52:16   6   END;
01:52:18   7  /
PL/SQL procedure successfully completed.
Elapsed: 00:00:28.79

  

  然后建立JAVA库.(你需要配置JAVA环境,也就是需要JDK+环境变量)

提示:这里可以直接利用ORACLE_HOME/JDK/BIN路径下的JAVAC来编译java文件.

编译ReadFile1.java,文件内容如下:

import java.io.*;
public class ReadFile1
{
// Convert the string to a file resource and call private method.
public static String readString(String s){
return readFileString(new File(s)); }
// Read an external file.
private static String readFileString(File file) {
// Define control variables.
int c;
String s = new String();
FileReader inFile;
try {
inFile = new FileReader(file);
while ((c = inFile.read()) != -1) {
s += (char) c; }
}
catch (IOException e) {
return e.getMessage(); }
return s; }
// Testing method.
public static void main(String[] args) {
String file = new String("/tmp/file.txt");
System.out.println(ReadFile1.readString(file)); }
}

  

将上面的java文件编译成ReadFile1.class后,使用loadjava工具将其加载到数据库中.

[oracle@oracleserver ~]$ ls ReadFile1*
ReadFile1.class
[oracle@oracleserver ~]$ loadjava -r -f -o -user scott/tiger ReadFile1.class
[oracle@oracleserver ~]$
  

没有提示,说明ReadFile1.class文件加载成功.
  
  发布java库(也就是定义和使用PL/SQL Library Wrapper调用java库)

注意JAVA库和PL/SQL也有数据类型的映射.LONG和LONG RAW数据类型最大只能为32K.

大多数类型的映射是简单的.


--建立函数,发布java类ReadFile1
02:14:34 SCOTT@orcl> CREATE OR REPLACE FUNCTION read_string(file IN VARCHAR2)
02:14:40   2  RETURN VARCHAR2 IS
02:14:40   3    LANGUAGE JAVA NAME 'ReadFile1.readString(java.lang.String) return String';
02:14:43   4  /
Function created.
Elapsed: 00:00:00.23

  

使用函数read_string读取/home/oracle/file.txt文件的内容.

--先在文件中写点内容
[oracle@oracleserver ~]$ echo Just a test>>file.txt
[oracle@oracleserver ~]$ more file.txt
Just a test
--然后使用函数读取
02:21:20 SCOTT@orcl> SELECT read_string('/home/oracle/file.txt') a FROM dual;
A
---------------
Just a test
1 row selected.
Elapsed: 00:00:00.01

  

6.外部存储故障诊断

外部存储的失败通常是因为两种原因.

一是监听的配置,共享库的配置、或者环境的配置.

以下错误比较常见:

1.监听的ENV参数不正确.

2.文件路径问题

3.监听中EXTPROC_DLLS参数值问题

4.extproc监听不正确或没有运行

5.没有单独的extproc监听

6.PL/SQL Wrapper定义的NAME值不正确


二是外部程序的定义和PL/SQL wrapper的定义不同.

这一般是由于数据类型的不正确转换导致的.

如错误:

BEGIN

*

ERROR at line 1:

ORA-28576: lost RPC connection to external procedure agent

ORA-06512: at "PLSQL.WRITE_STRING", line 1

ORA-06512: at line 4

这种错误是由于数据类型不能隐式转换时发生.

也就是当你尝试使用实际参数来fork外部库时,隐式转换到库的形式参数时发生的错误.

运维网声明 1、欢迎大家加入本站运维交流群:群②:261659950 群⑤:202807635 群⑦870801961 群⑧679858003
2、本站所有主题由该帖子作者发表,该帖子作者与运维网享有帖子相关版权
3、所有作品的著作权均归原作者享有,请您和我们一样尊重他人的著作权等合法权益。如果您对作品感到满意,请购买正版
4、禁止制作、复制、发布和传播具有反动、淫秽、色情、暴力、凶杀等内容的信息,一经发现立即删除。若您因此触犯法律,一切后果自负,我们对此不承担任何责任
5、所有资源均系网友上传或者通过网络收集,我们仅提供一个展示、介绍、观摩学习的平台,我们不对其内容的准确性、可靠性、正当性、安全性、合法性等负责,亦不承担任何法律责任
6、所有作品仅供您个人学习、研究或欣赏,不得用于商业或者其他用途,否则,一切后果均由您自己承担,我们对此不承担任何法律责任
7、如涉及侵犯版权等问题,请您及时通知我们,我们将立即采取措施予以解决
8、联系人Email:admin@iyunv.com 网址:www.yunweiku.com

所有资源均系网友上传或者通过网络收集,我们仅提供一个展示、介绍、观摩学习的平台,我们不对其承担任何法律责任,如涉及侵犯版权等问题,请您及时通知我们,我们将立即处理,联系人Email:kefu@iyunv.com,QQ:1061981298 本贴地址:https://www.iyunv.com/thread-242781-1-1.html 上篇帖子: Oracle表空间的创建与删除 下篇帖子: oracle数据库中文汉字排序
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

扫码加入运维网微信交流群X

扫码加入运维网微信交流群

扫描二维码加入运维网微信交流群,最新一手资源尽在官方微信交流群!快快加入我们吧...

扫描微信二维码查看详情

客服E-mail:kefu@iyunv.com 客服QQ:1061981298


QQ群⑦:运维网交流群⑦ QQ群⑧:运维网交流群⑧ k8s群:运维网kubernetes交流群


提醒:禁止发布任何违反国家法律、法规的言论与图片等内容;本站内容均来自个人观点与网络等信息,非本站认同之观点.


本站大部分资源是网友从网上搜集分享而来,其版权均归原作者及其网站所有,我们尊重他人的合法权益,如有内容侵犯您的合法权益,请及时与我们联系进行核实删除!



合作伙伴: 青云cloud

快速回复 返回顶部 返回列表