oracle 11g PL/SQL Programming学习十六
来源:互联网 发布:tfidf java高效 编辑:程序博客网 时间:2024/06/16 07:52
----------------------------------------------------------------------------
-----------------PL/SQL学习笔记系列 By Cryking-----------------
------------------------转载请注明出处,谢谢!------------------------
第15章 JAVA库
oracle 11g可以让你使用函数、存储、包来扩展你的应用.
你也可以在java编程语言里使用这些存储程序.
oracle 11g JVM新特性
oracle 11g JVM目前已经很成熟了.在11g,它有几点新特性:
1.oracle JVM内部兼容java 5标准版.
2.Oracle JVM得到增强.
包括支持了loadjava URL,dropjava基于列表的操作,使用ojvmmtc工具来解决外部类引用,增强了工具ojvmjava的功能.
3.引进了驻留数据库的JAR文件.
这意味着你当你加载JAR文件时,你现在可以选择创建一个代表JAR文件的对象.
4.在用户自定义类之间共享元数据的能力.
5.可以出现两重的java会话状态.
6.可以重定向输出流从数据库到外部.
7.可以设置在数据库服务器之间传播的系统属性
8.JIT编译器的交互减少了java字节流直接转换到特定代码,通过消除解释阶段来提高性能.
JAVA架构
oracle 11g提供了一个强健的架构来开发服务端或内部java程序组件.
JAVA和PL/SQL都是解释性语言,所以都需要JIT编译.
有三种方式将java class放到数据库实例里:
1.一个两步走的过程:a,使用JAVAC编译JAVA源文件,生成一个java字节代码程序.
b,使用loadjava工具将文件放入数据库实例.
2.一步走的过程:使用loadjava工具编译并把java类文件放入到数据库实例
3.一步走的过程:使用DDL来建立并编译java源文件作为java存储类.
java存储单元就像一般的PL/SQL程序单元.
当你有一个main()方法在java的资源类里,你只能通过ojvmjava工具来访问它,
内部java资源文件有两种表现:存储程序体和可实例化类.
java资源存储
java类资源以明文存储,是java字节代码,并且是压缩的java档案(也就是JAR文件).
JAR文件在11g里可以存储在数据库内部,也可以存储在数据库外.
java安全和许可
操作的资源是受限的.你只能使用SYSDBA权限来更改这些.
使用DBMS_JAVA包和GRANT_PERMISSION存储来打开受限的操作资源,像文件I/O.
java线程
java线程与oracle内部java类的工作方式是不同的.
oracle JVM使用的是非优先线程模型,也就是所有的线程都跑在一个操作系统的线程上面.
oracle 11g现在支持类加载,可以使你创建优先线程方案.
oracle java连接类型
oracle实现了三种java数据库连接方式以满足三种不同的需要.
它们是thin连接,thick连接,缺省连接.它们分别对应客户端驱动,中间件驱动,服务端驱动.
1.JDBC thin 驱动
oracle薄连接可能是java应用的最多的一种方式.JSP和EJB都使用这种方式.
它提供了很多方便,而不用直接访问oracle库文件.
乐观连接:乐观连接是使用HTTP协议的临时传输连接,它被限制在一个15秒的TCP套接字连接管道.
常用在JSP应用,它的缺点是必须为每个通信建立连接.
悲观连接:悲观连接是通常的连接方式,它使用一个可感知的TCP套接字在整个连接的过程中.
常用在使用多线程java servlets来创建和维护的数据库连接池中.
Java servlets能实现2层,甚至多层解决方案.
2.OCI驱动或中间层Thick驱动
OCI驱动和Oracle C/C++库紧密联系.
如果你使用ORACLE JDBC调用接口,你需要确保PATH、CLASSPATH、LD_LIBRARY_PATH环境变量设置正确.
OCI驱动能通过Java servlets来维护一个持久的连接池.
3.Oracle服务端内部驱动或服务层Thick驱动
Oracle服务端内部驱动也依赖Oracle C/C++库.
在服务端没有别的选择,只有用该驱动来建立JAVA程序作为存储对象.
它使用DriverManger类的getConnection()方法来连接到数据库.
Oracle服务端内部驱动要比Oracle JDBC thin驱动快,因为库就在本地,不用产生网络调用.
在Oracle数据库里建立java类库
有两种部署方法来建立java类库:
1.建立中间层调用接口驱动
调用接口库就像包含apache服务器的服务端.它们必须复制到所有的apache服务器节点,
然后使用web服务的负载均衡工具进行管理.
2.服务端java类库
服务端java类库基于Oracle JVM作为对象存储在数据库里.
本章主要讲这种方式的java类库.
java的配置及编译、运行见相关书籍,这里不详细介绍
注意:java的类名是大小写敏感的,并且文件名应当和类名一致
例:创建java文件HelloWorld1.java,内容如下:
public class HelloWorld1 {public static void main(String args[]) {System.out.println("Hello World."); }}
环境变量配置OK后,使用 javac HelloWorld1.java 命令来编译java文件HelloWorld1.
C:\Documents and Settings\Administrator>javac.exe E:\HelloWorld1.java
编译后会在源java文件目录下产生一个HelloWorld1.class类文件.
你可以通过命令 JAVA HelloWorld1来测试输出结果.
C:\Documents and Settings\Administrator>cd /d e:
E:\>java.exe HelloWorld1
Hello World.
建立和访问服务端java class文件分三步:
1.建立并编译java文件
2.使用loadjava工具将编译后的class文件加载到服务器
3.建立PL/SQL包装器来包装java calss库。
一个完整的例子(需要配置好JAVA环境变量):
创建java文件HelloWorld2.java,内容如下:
import oracle.jdbc.driver.*;// Class definition.public class HelloWorld2 {public static String hello() { return "Hello World."; }public static String hello(String name) { return "Hello " + name + "."; }public static void main(String args[]) { System.out.println(HelloWorld2.hello()); System.out.println(HelloWorld2.hello("Larry")); }}
编译该java文件
C:\Users\Administrator>javac C:\Users\Administrator\Desktop\HelloWorld2.java
C:\Users\Administrator>cd /d C:\Users\Administrator\Desktop
C:\Users\Administrator\Desktop>java HelloWorld2
Hello World.
Hello Larry.
注意:编译时可能会报找不到import oracle.jdbc.driver.*;包的错误,此时需要在环境变量CLASSPATH里加上classes12.jar
classes12.jar在oracle目录$ORACLE_HOME/oui/jlib下找到.
--使用loadjava工具将生成的class文件加载到oracle JVM
C:\Users\Administrator\Desktop>loadjava -r -f -o -user scott/tiger@orcl HelloWorld2.class
--建立pl/sql包来使用HelloWorld2中的方法hello22:21:14 SCOTT@orcl> CREATE OR REPLACE PACKAGE hello_world2 AS23:07:41 2 FUNCTION hello RETURN VARCHAR2;23:07:41 3 FUNCTION hello(who VARCHAR2) RETURN VARCHAR2;23:07:41 4 END hello_world2;23:07:41 5 /Package created.Elapsed: 00:00:00.1623:07:41 SCOTT@orcl> CREATE OR REPLACE PACKAGE BODY hello_world2 AS23:07:41 2 FUNCTION hello RETURN VARCHAR2 IS23:07:41 3 LANGUAGE JAVA NAME 'HelloWorld2.hello() return String';23:07:41 4 FUNCTION hello(who VARCHAR2) RETURN VARCHAR2 IS23:07:41 5 LANGUAGE JAVA NAME 'HelloWorld2.hello(java.lang.String) return String';23:07:42 6 END hello_world2;23:07:42 7 /Package body created.Elapsed: 00:00:00.0323:14:39 SCOTT@orcl> SELECT hello_world2.hello('Cryking!') FROM dual;HELLO_WORLD2.HELLO('CRYKING!')--------------------------------------------Hello Cryking!.1 row selected.Elapsed: 00:00:00.05
注意你使用的返回类型为varchar2,对应java中的类型string.这里需要写全(使用完全限定名):java.lang.String
还要注意HelloWorld2的名称以及方法hello的名称都是大小写敏感的,写错了,包也能正常创建,只是在使用包方法的时候会报错.
如我将上面'HelloWorld2.hello() return String'的内容改为 'HelloWorld2.HELLO() return String'
此时再使用会报错ORA-29531:
23:07:43 SCOTT@orcl> SELECT hello_world2.hello('Cryking!') FROM dual;SELECT hello_world2.hello('Cryking!') FROM dual *ERROR at line 1:ORA-29531: no method Hello in class HelloWorld2Elapsed: 00:00:00.04
在sql文件中创建java源
语法:
CREATE OR REPLACE AND RESOLVE JAVA SOURCE NAMED <java_class_name> AS
<java_source>
/
如:
23:14:41 SCOTT@orcl> CREATE OR REPLACE AND RESOLVE JAVA SOURCE NAMED HelloWorldSQL AS23:21:20 2 public class HelloWorldSQL {23:21:20 3 public static String hello() {23:21:20 4 return "Hello World."; }23:21:20 5 public static String hello(String name) {23:21:20 6 return "Hello " + name + "."; }23:21:20 7 }23:21:25 8 /Java created.Elapsed: 00:00:02.72
然后我们可以像上面一样,创建包来使用这个创建好的java源.
这个感觉比上面的loadjava方法要快捷许多.
23:21:29 SCOTT@orcl> CREATE OR REPLACE PACKAGE hello_world_sql AS23:24:05 2 FUNCTION hello RETURN VARCHAR2;23:24:05 3 FUNCTION hello(who VARCHAR2) RETURN VARCHAR2;23:24:05 4 END hello_world_sql;23:24:05 5 /Package created.Elapsed: 00:00:00.0823:24:05 SCOTT@orcl> CREATE OR REPLACE PACKAGE BODY hello_world_sql AS23:24:05 2 FUNCTION hello RETURN VARCHAR2 IS23:24:05 3 LANGUAGE JAVA NAME 'HelloWorldSQL.hello() return String';23:24:05 4 FUNCTION hello(who VARCHAR2) RETURN VARCHAR2 IS23:24:05 5 LANGUAGE JAVA NAME 'HelloWorldSQL.hello(java.lang.String) return String';23:24:05 6 END hello_world_sql;23:24:05 7 /Package body created.Elapsed: 00:00:00.0323:24:08 SCOTT@orcl> SELECT hello_world_sql.hello('Cryking!') FROM dual;HELLO_WORLD_SQL.HELLO('CRYKING!')---------------------------------Hello Cryking!.1 row selected.Elapsed: 00:00:00.0323:24:48 SCOTT@orcl> SELECT hello_world_sql.hello FROM dual;HELLO-------------Hello World.1 row selected.Elapsed: 00:00:00.01
建立服务端内部java存储过程
建立存储过程和建立上面的包内函数类似,不过应当注意的是存储过程有IN,IN OUT,OUT模式.
当在存储中使用了java方法时,不能使用IN OUT模式.
再看一个例子(在存储中使用java方法)
建立java文件HelloWorld3.java,内容如下:
import java.sql.*;import oracle.jdbc.driver.*;// Class definition.public class HelloWorld3 {public static void doDML(String statement,String name) throws SQLException {// Declare an Oracle connection.Connection conn = DriverManager.getConnection("jdbc:default:connection:");// Declare prepared statement, run query and read results.PreparedStatement ps = conn.prepareStatement(statement);ps.setString(1,name);ps.execute(); }public static String doDQL(String statement) throws SQLException {// Define and initialize a local return variable.String result = new String();// Declare an Oracle connection.Connection conn = DriverManager.getConnection("jdbc:default:connection:");// Declare prepared statement, run query and read results.PreparedStatement ps = conn.prepareStatement(statement);ResultSet rs = ps.executeQuery();while (rs.next())result = rs.getString(1);return result; }}
该java类有2个静态方法:1个是doDML,用来执行各种DML语句;另一个是doDQL,用来执行各个查询语句.
注意该java类没有main方法,不能直接测试,可以自己加个main来测试是否正常运行.
(我这里就不测试了)
C:\Users\Administrator\Desktop>javac C:\Users\Administrator\Desktop\HelloWorld3.java
C:\Users\Administrator\Desktop>loadjava -r -f -o -user scott/tiger@orcl HelloWorld3.class
导入到数据库之后,我们建立相关的包进行测试,注意doDML方法是使用存储过程来调用的
23:25:30 SCOTT@orcl> CREATE OR REPLACE PACKAGE hello_world3 AS23:37:08 2 PROCEDURE doDML(dml VARCHAR2, input VARCHAR2);23:37:08 3 FUNCTION doDQL(dql VARCHAR2) RETURN VARCHAR2;23:37:08 4 END hello_world3;23:37:08 5 /Package created.Elapsed: 00:00:00.0323:37:08 SCOTT@orcl> CREATE OR REPLACE PACKAGE BODY hello_world3 AS23:37:08 2 PROCEDURE doDML(dml VARCHAR2, input VARCHAR2) IS23:37:08 3 LANGUAGE JAVA NAME 'HelloWorld3.doDML(java.lang.String,java.lang.String)';23:37:08 4 FUNCTION doDQL(dql VARCHAR2) RETURN VARCHAR2 IS23:37:08 5 LANGUAGE JAVA NAME 'HelloWorld3.doDQL(java.lang.String) return String';23:37:08 6 END hello_world3;23:37:08 7 /Package body created.Elapsed: 00:00:00.0923:37:08 SCOTT@orcl> --建立测试表23:37:58 SCOTT@orcl> CREATE TABLE mytable(character VARCHAR2(100));Table created.Elapsed: 00:00:00.0623:38:49 SCOTT@orcl> --使用包hello_world3的java方法来插入和查询数据23:44:45 SCOTT@orcl> exec hello_world3.doDML('INSERT INTO MYTABLE VALUES(?)','Hello,Cryking!');PL/SQL procedure successfully completed.Elapsed: 00:00:00.0423:47:45 SCOTT@orcl> SELECT hello_world3.doDQL('SELECT CHARACTER FROM MYTABLE')a from dual;A--------------Hello,Cryking!1 row selected.Elapsed: 00:00:00.02
建立服务器内部java对象
需要使用SQLData接口来实例化存储的java对象.
主要注意数据类型的转换.
示例:
建立java文件HelloWorld4.java,内容如下:
import java.sql.*;import java.io.*;import oracle.sql.*;import oracle.jdbc.*;import oracle.jdbc.oracore.*;// Class definition.public class HelloWorld4 implements SQLData {// Define or declare SQLData components.private String className = new String("HelloWorld4.class");private String instanceName;private String qualifiedName;private String sql_type;public HelloWorld4() {String user = new String();try {user = getUserName(); }catch (Exception e) {}qualifiedName = user + "." + className; }// Define a method to return a qualified name.public String getQualifiedName() throws SQLException {// Declare return variable.return this.qualifiedName + "." + instanceName; }// Define a method to return the database object name.public String getSQLTypeName() throws SQLException {// Returns the UDT map value or database object name.return sql_type; }// Define getUserName() method to query the instance.public String getUserName() throws SQLException {String userName = new String();String getDatabaseSQL = "SELECT user FROM dual";// Declare an Oracle connection.Connection conn = DriverManager.getConnection("jdbc:default:connection:");// Declare prepared statement, run query and read results.PreparedStatement ps = conn.prepareStatement(getDatabaseSQL);ResultSet rs = ps.executeQuery();while (rs.next())userName = rs.getString(1);return userName; }// Implements readSQL() method from the SQLData interface.public void readSQL(SQLInput stream, String typeName) throws SQLException {// Define sql_type to read input and signal overloading signatures.sql_type = typeName;// Pass values into the class.instanceName = stream.readString(); }// Implements writeSQL() method from the SQLData interface with a placeholder.public void writeSQL(SQLOutput stream) throws SQLException {// You pass a value back by using a stream function./* stream.writeString(‘variable_name’); */ }}
然后我们不再使用javac来编译该java文件,而是用loadjava工具把该java文件直接加载到oracle里.
此时loadjava工具会帮我们完成编译java文件的工作.
C:\Users\Administrator\Desktop>loadjava -r -f -o -user scott/tiger@orcl HelloWorld4.java
--创建java对象类型23:48:02 SCOTT@orcl> CREATE OR REPLACE TYPE hello_world4 AS OBJECT00:04:04 2 EXTERNAL NAME 'HelloWorld4' LANGUAGE JAVA00:04:04 3 USING SQLData00:04:04 4 (instanceName VARCHAR2(100) EXTERNAL NAME 'java.lang.String'00:04:04 5 , CONSTRUCTOR FUNCTION hello_world400:04:04 6 RETURN SELF AS RESULT00:04:04 7 , MEMBER FUNCTION getQualifiedName00:04:04 8 RETURN VARCHAR2 AS LANGUAGE JAVA00:04:04 9 NAME 'HelloWorld4.getQualifiedName() return java.lang.String'00:04:04 10 , MEMBER FUNCTION getSQLTypeName00:04:04 11 RETURN VARCHAR2 AS LANGUAGE JAVA00:04:04 12 NAME 'HelloWorld4.getSQLTypeName() return java.lang.String')00:04:04 13 INSTANTIABLE FINAL;00:04:04 14 /Type created.Elapsed: 00:00:00.68
注意上面使用了USING SQLData子句,这样该对象类型不用再建立对象类型体了.
SQLData提供了存储对象的实例化接口.
在你定义了该java对象类型之后,你可以看到该对象类型和对象类型体都已经注册到oracle实例元数据里.
00:10:41 SCOTT@orcl> COL object_name FORMAT A3000:11:04 SCOTT@orcl> COL object_type FORMAT A1200:11:04 SCOTT@orcl> COL status FORMAT A700:11:05 SCOTT@orcl> SELECT object_name, object_type, status00:11:10 2 FROM user_objects00:11:10 3 WHERE object_name = 'HELLO_WORLD4';OBJECT_NAME OBJECT_TYPE STATUS------------------------------ ------------ -------HELLO_WORLD4 TYPE VALIDHELLO_WORLD4 TYPE BODY VALID2 rows selected.Elapsed: 00:00:00.01--直接使用该对象类型00:11:11 SCOTT@orcl> DECLARE00:13:21 2 -- Define and instantiate an object instance.00:13:21 3 my_obj1 hello_world4 := hello_world4('Adam');00:13:21 4 my_obj2 hello_world4 := hello_world4('Eve');00:13:21 5 BEGIN00:13:21 6 -- Test class instance.00:13:21 7 dbms_output.put_line('Item #1: [' || my_obj1.getQualifiedName || ']');00:13:21 8 dbms_output.put_line('Item #2: [' || my_obj2.getQualifiedName || ']');00:13:21 9 dbms_output.put_line('Item #3: [' || my_obj1.getSQLTypeName || ']');00:13:21 10 dbms_output.put_line('Item #4: [' || my_obj1.getSQLTypeName || ']');00:13:21 11 -- Test metadata repository with DBMS_JAVA.00:13:21 12 dbms_output.put_line('Item #5: [' || user || '.' ||00:13:21 13 dbms_java.longname('HELLO_WORLD4') || ']');00:13:21 14 END;00:13:21 15 /Item #1: [SCOTT.HelloWorld4.class.Adam]Item #2: [SCOTT.HelloWorld4.class.Eve]Item #3: [SCOTT.HELLO_WORLD4]Item #4: [SCOTT.HELLO_WORLD4]Item #5: [SCOTT.HELLO_WORLD4]PL/SQL procedure successfully completed.Elapsed: 00:00:00.03
这里你不能直接使用dropjava删除HelloWorld4.class,因为你loadjava的时候是加载的java文件.
--删除HelloWorld3.class是正常的,因为loadjava加载的是HelloWorld3.class
C:\Users\Administrator\Desktop>dropjava -u scott/tiger@orcl HelloWorld3.class
--直接删除报错
C:\Users\Administrator\Desktop>dropjava -u scott/tiger@orcl HelloWorld4.class
Error while dropping HelloWorld4
ORA-29537: 不能直接创建或删除类或资源
--这样才正确删除
C:\Users\Administrator\Desktop>dropjava -u scott/tiger@orcl HelloWorld4.java
- oracle 11g PL/SQL Programming学习十六
- oracle 11g PL/SQL Programming学习一
- oracle 11g PL/SQL Programming学习二
- oracle 11g PL/SQL Programming学习三
- oracle 11g PL/SQL Programming学习四
- oracle 11g PL/SQL Programming学习五
- oracle 11g PL/SQL Programming学习六
- oracle 11g PL/SQL Programming学习七
- oracle 11g PL/SQL Programming学习八
- oracle 11g PL/SQL Programming学习九
- oracle 11g PL/SQL Programming学习十
- oracle 11g PL/SQL Programming学习十一
- oracle 11g PL/SQL Programming学习十二
- oracle 11g PL/SQL Programming学习十三
- oracle 11g PL/SQL Programming学习十四
- oracle 11g PL/SQL Programming学习十五
- oracle 11g PL/SQL Programming学习十七
- Oracle Database 11g PL/SQL Programming
- 使用CursorLoader异步加载数据
- VIM命令总结
- Hibernate笔记1
- JVM学习之二:内存管理
- avi文件格式解析
- oracle 11g PL/SQL Programming学习十六
- 姜迅谈阿里设计数据架构和经验
- JMF支持的AVI支持的视屏音频编码方式
- Ruby On Rails 开发学习笔记(一)
- ASP.NET生成excel失败(异常来自 HRESULT:0x800A03EC )
- 黑马程序员_IO流(二)
- Android:layout_weight
- IOS设计模式之MVC模式
- HDU2133(日期计算)