当前位置:文档之家› DB2 SQLJ 存储过程开发宝典,第 2 部分_217_IT168文库

DB2 SQLJ 存储过程开发宝典,第 2 部分_217_IT168文库

DB2 SQLJ 存储过程开发宝典,第 2 部分简介: 在第 1 部分,我们已经介绍了 SQLJ 存储过程的基本知识,如何逐步完成开发和调试。

现在,我们将总结说明在运行 SQLJ 存储过程时,经常遇到的错误,并对这些错误产生的原因进行分析,并给出相应的修正方法。

此外,在开发过程中,有一些值得考虑或者需要进一步说明的问题,我们也将他们罗列出来,予以探讨。

引言在第 1 部分,我们已经介绍了 SQLJ 存储过程的基本知识,如何逐步完成开发和调试。

现在,我们将总结说明在运行 SQLJ 存储过程时,经常遇到的错误,并对这些错误产生的原因进行分析,并给出相应的修正方法。

此外,在开发过程中,有一些值得考虑或者需要进一步说明的问题,我们也将他们罗列出来,予以探讨。

常见错误总结由于程序代码本身、运行环境、参数配置等原因,SQLJ 存储过程在被调用时,可能会发生各种错误。

对这些错误进行分析,明确其产生的原因,找到相应的应对措施,并加以归纳总结,对我们提高开发水平、保证产品质量和提高工作效率等方面具有重要的意义。

这些信息对于 SQLJ 应用开发的初学者尤为重要,能够直接的帮助他们解决开发实际工作中遇到的问题,表 1 列出了常见的 SQLJ 存储过程运行错误,原因以及相应措施。

表 1. 常见错误错误原因措施SQL4306N Java 存储过程或用户定义的函数 名称(特定名称 特定名称)不能调用 Java 方法 方法,特征符为 字符串 DB2 通过 JAR 包名、类名、方法名和签名(Signature )无法找到创建存储过程时指定的被调用的方法。

可能是引用的类不存在、jar 包没有安装、方法声明的参数列表与数据库期望的参数列表不匹配或者不是“public”实例方法 1.查看 Java 代码中的方法名和类名,检查存储过程DDL 中 Java 方法名、类名和 jar 包名是否有误; 2.检查 jar/calss 文件是否在指定位置,如 sqllib/function 目录下; 3.检查存储过程 DDL 中的方法参数列表是否与 Java 代码匹配(使用 javap – s class_id 可以查看类中方法的签名),并且 Java 代码中该方法是 public的。

SQL4304N Java 存储过程或用户定义的函数 名称(特定名称 特定名称)不能装入 Java 类 类,原因码为 原因码。

1. RC=1:在 CLASSPATH 上找不到该类。

往往可能是我们在DDL 发生了拼写错误;2. RC=2:该类未实现必需的接口 COM.ibm.db2.app.StoredProc或缺少 public 访问权标志。

如果是 PARAMETER STYLEDB2GENERAL 的存储过程,那么要求被调用 Java 类是 public的并继承了接口 COM.ibm.db2.app.StoredProc 。

1.检查 Java 代码中的类 / 方法名和存储过程 DDL中 Java 类 / 方法名是否一致;2.检查 jar/calss 文件是否在 CLASSPATH 中,如sqllib/function 目录下;3.检查是否 DDL 指定了 PARAMETER STYLEDB2GENERAL 而 Java 代码类是否是 public 并继承接口 COM.ibm.db2.app.StoredProc 。

SQL4302N过程或用户定义的函数 名称(特定名称 特定名称)由于异常 字符串 而存储过程由于异常而异常终止。

通常可能是查询返回是空的数据集,或是 SQL 中使用“select into :hostvar”但是实际查询返回多条数据,或 Java 运行中出现空指针异常等。

检查 db2diag.log 诊断日志,找到错误,修正 Java代码。

异常终止。

SQL4301NJava 或 .NET 解释器启动或通信失败,原因码为 原因码。

启动或与 JVM 通信时出错。

可能是因为 Java 环境变量或 Java 数据库配置参数无效,如 JDK_PATH 和 JAVA_HEAP_SZ 配置失当 或 db2java.zip 不在 CLASSPATH 中等。

确保正确设置了 Java 数据库配置参数(jdk_path 和 java_heap_sz )。

确保安装了支持的 Java 运行时环境。

确保内部 DB2 类(COM.ibm.db2)未被用户类覆盖。

1. 检查 jdk_path 是否指向 JDK 的 bin 目录的父目录,CLASSPATH 中包含 db2java.zip ;2. 检查是否指定了足够大的 java_heap_sz 。

SQL20204N 用户定义的函数或过程 函数名 无法映射至单个 Java 方法。

存储过程找不到匹配的 Java 方法,或者找到多个匹配的 Java 方法。

理解 EXTERNAL NAME 的规范格式 [jar_id]:class_id(.|!)method_id ,即“:”分隔包名和类名,“.”或“!”分隔类名和方法名,包名可选。

1.检查 DDL 是否指定了正确的 Java 方法名、类名和 jar 包名; 2.检查 jar/calss 文件是否存在,如在 sqllib/function目录下;3.检查是否有方法参数列表匹配问题。

SQL1042C 发生了意外的系统错误。

运行存储过程是出现该错误,往往是因为 DB2 实例级别的环境问题、访问权限问题或参数配置问题。

如 Java 程序访问无权访问的文件、DB2 参数 DB2_FMP_COMM_HEAPSZ 设置为零等。

检查 db2diag.log 诊断日志,找到系统错误的原因并予以修正。

如正确配置文件的访问权限,Java 代码中只读写可读写的文件等。

更详细的信息,请参考文章 解决 DB2 UDB Java 存储过程的常见问题。

进一步探讨的若干问题为了介绍的简明和连贯,在第 1 部分 SQLJ 存储过程的开发实例中,我们使用了比较简练的示例,分步骤说明如何完成 SQLJ 存储过程的编码和调试,没有展开篇幅,引入更多的讨论。

下面我们以问答的形式,介绍在 SQLJ 存储过程的开发中,我们需要知晓的一些其它问题。

1. 如果不把 SQLJ 概要文件绑定到特定的数据库,可以运行 SQLJ 存储过程吗?可以。

在 SQLJ 应用开发模型和 SQLJ 存储过程开发流程的介绍中,我们都介绍了需要将 SQLJ 概要文件定制到特定的数据库。

更进一步,在定制概要文件成功后,概要文件将被更新,增加定制信息,包括 DB2 package 名称和时间戳等内容。

在执行 SQLJ 应用时,如果发现概要文件中含有定制信息,那么将使用生成的 DB2 package ,运行静态 SQL ,反之,如果概要文件中没有定制信息,那么将按动态 SQL 完成数据库操作。

所以仅从 SQLJ 存储过程能否运行来说,概要文件定制这一步骤不是必需的。

跳过这一步,SQLJ 存储过程仍然可以运行,但是 DB2 概要文件中没有任何定制化信息,存储过程将退化为动态执行 SQL 的 Java 应用,与直接使用 JDBC 编写的 Java 存储过程一样,但是这显然不是我们使用 SQLJ 的目的,所以一般情况下,我们都需要定制 SQLJ 概要文件。

2. 可以在同一 Java 源文件中,同时使用 SQLJ 和 JDBC 吗?可以。

SQLJ 和 JDBC 可以共享数据库连接,SQLJ 可以从 JDBC 的连接(connection)为参数创建连接上下文(connection context),JDBC 也可以从 SQLJ 连接上下文中获得连接,这样,SQLJ 和 JDBC 在同一数据库连接,可以共享事务单元;SQLJ 和 JDBC 也可以相互传递从数据库中返回的查询结果,可以通过 SQLJ 的迭代器的 getResultSet() 方法,得到JDBC 的 ResultSet。

也可以通过 CAST 语句将 JDBC 的 ResultSet 转换为 SQLJ 的迭代器。

参见清单 1。

清单1. SQLJ 和JDBC 交互的示例??????????????????????????????????//...MyContext ctx = new MyContext("jdbc:default:connection", false);#sql [ctx] { INSERT INTO tableName (objId, col) VALUES (2, 'sales') };// 由 SQLJ 连接上下文获得 JDBC 连接Connection dbcon = ctx.getConnection();// 以 JDBC 连接为参数创建 SQLJ 连接上下文MyContext newCtx = new MyContext(dbcon);#sql [newCtx] { INSERT INTO tableName (objId, col) VALUES (3, 'orders') };//SQLJ 的迭代器传递数据给 JDBC 的 ResultSet#sql [newCtx] myCursor = { SELECT col FROM tableName };ResultSet rs = myCursor.getResultSet();while (rs.next()) {System.out.println(rs.getString(1));}//JDBC 的 ResultSet 传递数据给 SQLJ 的迭代器Statement stmt = dbcon.createStatemnt();ResultSet rs = stmt.executeQuery("SELECT col FROM tableName");#sql myCursor = { CAST :rs };while (myCursor.next()) {System.out.println(());3. 示例中所有 SQLJ 语句中都指定了连接上下文,它们可以省略吗?有关 SQLJ 上下文的使用,情况稍微有点复杂。

在本文前面的示例代码中,均使用了“#sql [ctx] { SQL statement};”格式嵌入 SQL 语句,但是如果我们使用的是 DB2 v8 之前的版本中,那么也可以省略 [ctx],即“sql { SQL statement};”,这时我们使用的是缺省的连接上下文,代码片段如清单 2 所示。

清单2. 在DB2 v8 之前的版本中使用缺省上下文?????????????????????????public class MyClass {public static void MyMethod(int objectID, String[] colName){//...try {DefaultContext ctx = DefaultContext.getDefaultContext();#sql { SELECT col into :hostVar FROM tableName WHERE objID=:objectID };//...} catch (SQLException e) {//Log error message}} // end of MyMethod} // end of MyClass正如在第 1 部分讨论连接上下文时所指出的,在新的 DB2 版本中,我们不能以清单 2 中的方法创建和使用缺省上下文,因为在多线程的环境下使用同一连接上下文,将可能导致不可预测的后果。

相关主题