简介
在数据库应用程序中使用存储过程有许多好处,包括减少对网络的使用、提高性能以及降低开发成本。Java 存储过程是 DB2 支持的最流行的例程之一。原因之一是,由于 Java 编程语言非常流行,所以 Java 开发人员非常多。因此,在有多种语言可供选择时,Java 例程往往是首选的。
DB2 存储过程不一定非用 Java 来编写。如果业务逻辑只需要简单的存储过程,那么可以考虑用 SQL Procedure Language(SQL PL)进行存储过程开发。SQL 存储过程总是作为 受信任的 存储过程运行,并且因为它们不依赖于外部 Java 虚拟机(Java Virtual Machine,JVM)进程来装载过程,所以比 Java 例程快。
使用 Java 存储过程的好处与创建 Java 应用程序时获得的好处相同。Java 是非常安全的编程语言。用户只能获得 Java 字节码。Java 代码编译一次,就能够在支持 JVM 的任何计算机和操作系统上运行。因为 Java 代码在单独的 JVM 中运行,所以 JVM 能够正确地处理(可能导致 JVM 崩溃的)危险操作。不需要实现单独的基础设施来处理危险状况,因为 Java 具有捕获异常的内置机制。
在本文中,我们有时将 Java 存储过程称为例程。在 DB2 UDB 中存储过程和例程是同义的。在 DB2 V8 中引入了例程的概念,它既表示存储过程,也表示用户定义函数(UDF)。
本文讨论在开发或运行 Java 存储过程的过程中可能遇到的常见错误消息。在开始讨论之前,我们先讨论 Java 存储过程开发的重要概念和配置参数。接下来,描述如何启用 DB2 Java。需要建立 Java 环境才能成功地调用 Java 存储过程。
关键概念
以下概念对于理解存储过程在 DB2 环境中如何工作非常重要:
FENCED 或 NOT FENCED: 这个子句指定例程是否被认为可以在数据库管理器操作环境的进程或地址空间中“安全地”运行。
如果存储过程被注册为 FENCED,那么数据库管理器就禁止过程访问它的内部资源(比如数据缓冲区)。大多数例程都有作为 FENCED 或 NOT FENCED 运行的选项。但是,Java 例程只能注册为 FENCED。一般来说,作为 FENCED 运行的例程执行得没有作为 NOT FENCED 运行的相似例程那么快。这是因为 NOT FENCED 例程可以在数据库引擎内利用进程间通信(IPC)。
对没有经过彻底测试的例程使用 NOT FENCED,可能会破坏 DB2 完整性。DB2 对于许多常见的意外故障类型采取了某些保护措施,但是在使用 NOT FENCED 例程时无法保证完全的完整性。NOT FENCED 例程常常被称为受信任的(trusted)。声明为受信任的例程在数据库管理器的地址空间中运行。
将例程注册为 NOT FENCED 需要 SYSADM 特权、DBADM 特权或一个特殊的特权(CREATE_NOT_FENCED)。定义为 NOT THREADSAFE 的例程只能指定 FENCED。
THREADSAFE 或 NOT THREADSAFE: 这个子句指定这个例程是否可以安全地在其他例程的进程中执行(THREADSAFE 是可以,NOT THREADSAFE 是不可以)。
如果过程定义为 THREADSAFE,数据库管理器就可以在其他例程的进程中调用这个过程。一般来说,要想定义为 THREADSAFE,例程不应该使用任何全局或静态数据区域。许多编程参考资料讨论了如何编写线程安全的例程。FENCED 和 NOT FENCED 过程都可以是 THREADSAFE 的。
如果过程定义为 NOT THREADSAFE,数据库管理器就绝不会在其他例程的进程中调用这个过程。
在 Java 存储过程中,THREADSAFE 是默认的,无论它被声明为 FENCED 还是 NOT FENCED 存储过程。
配置参数
DB2 有许多配置参数。一些参数在数据库级上定义,其他参数在数据库管理级上定义。影响存储过程行为的大多数参数是在实例级(即数据库管理级)上定义的。
KEEPFENCED: 这是一个数据库管理器配置(DBM CFG)参数。在以前的 DB2 UDB 版本中,它被称为 KEEPDARI。这个参数指出,在完成一个防护模式例程调用之后,是否保留防护模式进程(db2fmp)。防护模式进程是作为单独的系统实体创建的,以便将用户编写的防护模式代码与数据库管理器代理进程隔离开来。这个参数只能应用于数据库服务器。在开发存储过程时,强烈建议将这个参数设置为 NO,这样,调用存储过程时总会得到全新的存储过程副本。如果存储过程常常重新编译,那么这特别重要。在生产环境中,应该将这个参数设置为 YES,因为它会显著地影响性能。NOT FENCED 存储过程不受这个配置参数影响,因为它们不在 db2fmp 进程中运行。
FENCED_POOL: 这是一个数据库管理器配置(DBM CFG)参数。它代表系统上缓存的空闲防护模式进程(db2fmp)的数量。对于线程化的 db2fmp 进程(为线程安全的存储过程和 UDF 提供服务的进程),这个参数代表每个 db2fmp 进程中缓存的线程数量。对于非线程化的 db2fmp 进程,这个参数代表缓存的进程数量。
NUM_INITFENCED: 这是一个数据库管理器配置(DBM CFG)参数。这个参数表示在 DB2START 时在 db2fmp 池中创建的非线程化空闲 db2fmp 进程的初始数量。如果没有指定 KEEPFENCED,这个参数就被忽略。
JDK_PATH: 这是一个数据库管理器配置(DBM CFG)参数。这个参数指出用来执行 Java 存储过程的 JVM 或 Java Development Kit(JDK)的位置。这是一个非常重要的参数。它的值应该设置为包含 JVM Java 可执行文件的 “bin” 目录的上一级目录的完整路径。在 Windows® 平台上的一个例子是 C:\Program Files\IBM\SQLLIB\java\jdk。UNIX® 例子是 /usr/java1.3.1。JVM 级别也非常重要,因为根据使用的 db2level 和平台级别,DB2 UDB 只支持某些 JVM 级别。(这个问题将在本文稍后讨论。)
JAVA_HEAP_SZ: 这是一个数据库管理器配置(DBM CFG)参数。这个参数决定为 Java 存储过程和 UDF 服务的 Java 解释器所使用的堆的最大大小。为了避免在 Java 存储过程中耗尽内存,可以增加这个值。但是,如果在环境中要调用许多存储过程(即,每个 JVM 都会分配这么多堆空间),那么分配太多内存也是有害的。一般规则是保持 JAVA_HEAP_SZ 为默认设置,即 512(4K 页)。
ASLHEAPSZ: 这是一个数据库管理器配置(DBM CFG)参数。应用程序支持层堆是本地应用程序和与它相关联的代理之间的通信缓冲区。这个缓冲区作为每个数据库管理器代理共享的内存分配。这个参数确定缓冲区的大小,用于在例程和发出调用的应用程序之间传递参数。存储过程中的参数数量和参数大小明确地影响这个配置参数。系统上允许同时存在的 db2fmp 进程的最大数量也受这个参数的影响。
QUERY_HEAP_SZ: 这是一个数据库管理器配置(DBM CFG)参数。这个参数指定可以分配给查询堆的最大内存量。查询堆用于在代理的私有内存中存储每个查询。每个查询的信息包括输入和输出 SQLDA、语句文本、SQLCA、包名、创建者、区号和一致性符号。提供这个参数是为了确保应用程序不会不必要地消耗代理中的大量虚拟内存。如果这个参数设置得过低,那么执行复杂 SQL 的存储过程会导致 db2fmp 进程意外终止。
DB2_FMP_COMM_HEAPSZ: 这是一个 db2set 注册表参数。这个参数可应用于所有平台,只有 AIX 32 位平台除外,在这种平台上这个值预定义为 256MB。这个变量指定防护例程调用(比如存储过程或用户定义函数调用)所使用的池的大小(以 4 KB 页为单位)。每个防护例程所使用的空间是 ASLHEAPSZ 配置参数值的两倍。如果在系统上运行大量防护例程,那么可能需要增加这个变量的值。如果运行的防护例程很少,可以降低这个值。将这个值设置为 0 就表示不创建池,因此不能调用防护例程。可以用以下公式计算系统上可以同时运行的 db2fmp 进程的数量:
Maximum Number of db2fmps = DB2_FMP_COMM_HEAPSZ / (2*ASLHEAPSZ)
设置 Java 环境
需要执行几个步骤,然后才能编译 Java 存储过程。本节讨论设置用于运行 Java 过程的系统所需的步骤。
兼容的 JDK/JVM 级别
在开始之前,首先确保数据库服务器上安装了兼容的 JDK/JVM。每种操作系统支持不同的 JDK 级别。如果数据库实例配置为 64 位而不是 32 位,那么这特别重要。
同一个系统上可以安装多个 JVM。为了决定在执行 Java 存储过程时使用哪个 JVM,DB2 读取 JDK_PATH 数据库管理器配置参数。需要确保 JDK_PATH 指向与环境兼容的 JVM。
设置 Java 环境
DB2 数据库服务器的平台需要正确地设置才能使用 Java。对于 Java 支持,每种平台可能有自己的需求。
对于 UNIX 平台一般的 Java 设置需求可以在以下网页上找到:http://publib.boulder.ibm.com/infocenter/db2help/topic/com.ibm.db2.udb.doc/ad/t0004675.htm
对于 Windows 平台一般的 Java 设置需求可以在以下网页上找到:http://publib.boulder.ibm.com/infocenter/db2help/topic/com.ibm.db2.udb.doc/ad/t0006428.htm
HPUX 和 Linux
HPUX 和 Linux 对于 Java 支持有额外的需求:
HPUX 的需求细节可以在以下网页上找到:http://publib.boulder.ibm.com/infocenter/db2help/topic/com.ibm.db2.udb.doc/ad/t0004877.htm
Linux 的需求细节可以在以下网页上找到:http://publib.boulder.ibm.com/infocenter/db2help/topic/com.ibm.db2.udb.doc/ad/t0004878.htm。关于 Linux 设置的更多信息还可以在以下网页上找到: http://publib.boulder.ibm.com/infocenter/db2help/topic/com.ibm.db2.udb.doc/core/r0012306.htm#wq39(请查看 “Setting up the Linux Java environment” 小节)
防护 id
为了执行 FENCED 存储过程,DB2 通过防护 id 方式提供了额外的安全层。这个 id(和组)应该在创建 DB2 实例时创建。可以从以下网页获得关于这个 id 的更多信息:http://publib.boulder.ibm.com/infocenter/db2help/topic/com.ibm.db2.udb.doc/admin/t0005077.htm
配置参数