写了一个简单的JAVA存储过程,处理一个精度较大的数学问题,结果碰到了ORA-24345错误。
由于对JAVA不熟悉,JAVA存储过程也很少使用,因此费了不少时间,总算写了出来,但是在执行的时候发现了一个问题。
这个存储过程是用来计算圆周率的取值的,相关算法可以参考:http://yangtingkun.itpub.net/post/468/468870
关于存储过程就不详细描述了,下面直接看问题的产生:
SQL> create or replace and compile java source named "pi" as
2 import java.math.BigDecimal;
3 public class pi extends Object
4 {
5 public static String pi (int n)
6 {
7 BigDecimal result = new BigDecimal(1);
8 for (int i=n;i>0;i--)
9 {
10 BigDecimal temp = new BigDecimal(i);
11 result = new BigDecimal(2).add
12 (result.multiply
13 (temp.divide(new BigDecimal(1).add
14 (temp.multiply
15 (new BigDecimal(2))
16 ),102,BigDecimal.ROUND_HALF_UP)
17 )
18 );
19 }
20 return result.toString();
21 }
22 }
23 /
Java 已创建。
SQL> create or replace function f_pi (p_n in number) return varchar2 as
2 language java name 'pi.pi(int) return String';
3 /
函数已创建。
下面是调用结果:
SQL> select f_pi(10) from dual;
F_PI(10)
----------------------------------------------------------------------------------------------------
3.14084209564085725076437150740556313311731268387615136841143033093497489782319503681732783899966562
SQL> select f_pi(20) from dual;
F_PI(20)
----------------------------------------------------------------------------------------------------
3.14159211320774327955203808659259711079349608208228689356906807763678437061385664739133875908352702
SQL> select f_pi(50) from dual;
select f_pi(50) from dual
*
第 1 行出现错误:
ORA-24345: 出现截断或空读取错误
ERROR:
ORA-01002: 提取违反顺序
未选定行
数据量比较小的时候没有问题,一旦输入参数值比较大,就会出现上面的这个错误。
测试还发现,如果将java存储过程中的除法保留小数位数缩小一些,上面的查询就可以得到结果,但是如果继续增大数据量仍然会导致错误:
SQL> create or replace and compile java source named "pi" as
2 import java.math.BigDecimal;
3 public class pi extends Object
4 {
5 public static String pi (int n)
6 {
7 BigDecimal result = new BigDecimal(1);
8 for (int i=n;i>0;i--)
9 {
10 BigDecimal temp = new BigDecimal(i);
11 result = new BigDecimal(2).add
12 (result.multiply
13 (temp.divide(new BigDecimal(1).add
14 (temp.multiply
15 (new BigDecimal(2))
16 ),10,BigDecimal.ROUND_HALF_UP)
17 )
18 );
19 }
20 return result.toString();
21 }
22 }
23 /
Java 已创建。
SQL> select f_pi(100) from dual;
select f_pi(100) from dual
*
第 1 行出现错误:
ORA-29549: 类YANGTK.pi已更改, Java 会话状态被清除
SQL> select f_pi(100) from dual;
F_PI(100)
----------------------------------------------------------------------------------------------------
3.14159265347479757400080071875069256317928871566570517689083488598820471276504302524793754286818752
SQL> select f_pi(200) from dual;
F_PI(200)
----------------------------------------------------------------------------------------------------
3.14159265347479757400080071875090016088532653926425891578738668564238870675937454358049319246851093
SQL> select f_pi(500) from dual;
select f_pi(500) from dual
*
第 1 行出现错误:
ORA-24345: 出现截断或空读取错误
ERROR:
ORA-01002: 提取违反顺序
未选定行
开始认为是JAVA缓冲区的问题,不过当前系统的SGA和PGA的大小对于这个计算应该是绰绰有余的:
SQL> SHOW SGA
Total System Global Area 603979776 bytes
Fixed Size 1249332 bytes
Variable Size 239079372 bytes
Database Buffers 356515840 bytes
Redo Buffers 7135232 bytes
SQL> SHOW PARAMETER SGA_TARGET
NAME TYPE VALUE
------------------------------------ ----------- ------------
sga_target big integer 576M
SQL> SHOW PARAMETER PGA
NAME TYPE VALUE
------------------------------------ ----------- ------------
pga_aggregate_target big integer 191M
查询了一下错误文档:
ORA-24345: A Truncation or null fetch error occurred
Cause: A truncation or a null fetch error"
Action: Please ensure that the buffer size is long enough to store the returned data.
这个描述就比较清晰了,由于VARCHAR2长度的限制导致了JAVA存储过程返回的结果没有办法传递给PL/SQL。
那么只需要修改一下JAVA代码,返回适当长度的字符串即可:
SQL> create or replace and compile java source named "pi" as
2 import java.math.BigDecimal;
3 public class pi extends Object
4 {
5 public static String pi (int n)
6 {
7 BigDecimal result = new BigDecimal(1);
8 for (int i=n;i>0;i--)
9 {
10 BigDecimal temp = new BigDecimal(i);
11 result = new BigDecimal(2).add
12 (result.multiply
13 (temp.divide(new BigDecimal(1).add
14 (temp.multiply
15 (new BigDecimal(2))
16 ),102,BigDecimal.ROUND_HALF_UP)
17 )
18 );
19 }
20 return result.toString().substring(0,102);
21 }
22 }
23 /
Java 已创建。
SQL> select f_pi(100) from dual;
select f_pi(100) from dual
*
第 1 行出现错误:
ORA-29549: 类YANGTK.pi已更改, Java 会话状态被清除
SQL> select f_pi(100) from dual;
F_PI(100)
----------------------------------------------------------------------------------------------------
3.14159265358979323846264338327929528649084412679106662169776161333278097211785395952441592543372994
来自 “ ITPUB博客 ” ,链接:http://blog.itpub.net/4227/viewspace-429853/,如需转载,请注明出处,否则将追究法律责任。
转载于:http://blog.itpub.net/4227/viewspace-429853/