今天碰到一个很有意思的错误,通过JAVA程序连接数据库,运行程序时报错,错误信息就是ORA-00942: table or view does not exist。
这篇描述重现问题过程。
一次ORA-942错误的跟踪(一):http://yangtingkun.itpub.net/post/468/480559
一次ORA-942错误的跟踪(二):http://yangtingkun.itpub.net/post/468/480671
一次ORA-942错误的跟踪(三):http://yangtingkun.itpub.net/post/468/480744
一次ORA-942错误的跟踪(四):http://yangtingkun.itpub.net/post/468/480825
在上面一篇文章中,已经最终定位了问题产生的原因,并找到了Oracle对应的BUG描述,验证了解决这个问题的方法。可以说这个问题已经被解决了。
不过对于真正理解这个问题而言,还差一个关键的步骤,就是重现问题。
通过人为的构造一个最简单的环境来再现问题,对于将问题提交给Oracle的支持部门或向其他人提问等情况是十分有帮助的。如果看不到环境,没有办法动手进行测试,是很难确定问题的原因的。因此能够在本地重现问题,被定位并解决的可能性要大得多。
而且重现问题本身也是一个解决问题的一部分。通过构造一个最简单的环境在重现问题,可以将问题相关的因素搞清楚。一般来说,一个问题可能和数据库中的很多因素有关。通过重现这个问题,可以最终确定是哪些因素导致了错误的发生。
举一个例子:在Oracle的9204上碰到了一个SQL问题,FIRST_ROWS优化模式下,通过数据库链访问远端表,且SQL包括IN子查询语句时,优化器可能给出错误的执行计划,从而导致结果集出现重复记录。对于这个错误,可能与Oracle的版本、所在平台、分布式查询、IN查询子句、CBO优化模式等多个因素有关。确定导致问题的原因本身就比较困难。那么可以通过重现问题的方式来确定导致问题的原因。具体方法是每次测试的时候减少一个可能影响问题的因素,然后检查问题是否可以重现。比如换一个10g的数据库环境执行相同的SQL,如果仍然出现问题,说明这个问题和多个数据库版本都有关系,如果不出现问题,说明9204版本是导致问题出现的一个因素。然后9204版本中,访问本地表,检查问题是否可以重现,如果能够重现,说明问题与是否访问远端对象无关,反之说明访问远端对象也是影响问题的因素之一。通过不断的测试,最终找到导致并引发问题的所有原因。在构造最简单的重现错误的环境的过程中,已经将问题导致的原因确定清楚了。
对于当前这种情况,错误的原因已经清楚了,解决错误的方法也找到了。那么重现问题是否还有意义呢?答案仍然是有意义。因为重现问题的过程,可以验证你对问题的理解是否正确。如果你的理解是正确的,那么就可以很轻松的在线这个错误。如果你无法在线这个错误,那么肯定是你的理解不正确,后者说你还漏掉了一些很关键的因素。
下面在Oracle 10.2.0.3 for Solaris平台下模拟这个错误:
SQL> SELECT * FROM V$VERSION;
BANNER
----------------------------------------------------------------
Oracle Database 10g Enterprise Edition Release 10.2.0.3.0 - 64bi
PL/SQL Release 10.2.0.3.0 - Production
CORE 10.2.0.3.0 Production
TNS for Solaris: Version 10.2.0.3.0 - Production
NLSRTL Version 10.2.0.3.0 - Production
SQL> CREATE USER A1 IDENTIFIED BY A1 DEFAULT TABLESPACE USERS;
用户已创建。
SQL> CREATE USER A2 IDENTIFIED BY A2 DEFAULT TABLESPACE USERS;
用户已创建。
SQL> CREATE USER B1 IDENTIFIED BY B1 DEFAULT TABLESPACE USERS;
用户已创建。
SQL> CREATE USER B2 IDENTIFIED BY B2 DEFAULT TABLESPACE USERS;
用户已创建。
SQL> GRANT CONNECT, RESOURCE TO A1;
授权成功。
SQL> GRANT CONNECT, RESOURCE TO B1;
授权成功。
SQL> GRANT CREATE SESSION, CREATE SYNONYM TO A2;
授权成功。
SQL> GRANT CREATE SESSION, CREATE SYNONYM TO B2;
授权成功。
SQL> CONN A1/A1
已连接。
SQL> CREATE TABLE T (ID NUMBER);
表已创建。
SQL> GRANT SELECT ON T TO A2;
授权成功。
SQL> CONN A2/A2
已连接。
SQL> CREATE SYNONYM T FOR A1.T;
同义词已创建。
SQL> SELECT * FROM T;
未选定行
SQL> CONN B1/B1
已连接。
SQL> CREATE TABLE T (ID NUMBER);
表已创建。
SQL> GRANT SELECT ON T TO B2;
授权成功。
SQL> CONN B2/B2
已连接。
SQL> CREATE SYNONYM T FOR A2.T;
同义词已创建。
SQL> SELECT * FROM T;
SELECT * FROM T
*
第 1 行出现错误:
ORA-00942: 表或视图不存在
SQL> DROP SYNONYM T;
同义词已删除。
SQL> CREATE SYNONYM T FOR B1.T;
同义词已创建。
SQL> SELECT * FROM T;
SELECT * FROM T
*
第 1 行出现错误:
ORA-00942: 表或视图不存在
SQL> SELECT * FROM t;
未选定行
SQL> SELECT * FROM T A;
未选定行
简单描述一下重现的步骤,首先建立了4个用户,A1、A2、B1和B2。其中A1和B1中建立了表,并把查询权限分别授予A2和B2。
在A2中建立指向A1的同义词,并进行访问。
在B2中建立指向A1或A2的同义词,访问时会报错,这是由于B2没有访问A1对象的权限。
将B2的同义词删除,并指向B1的对象。这时B2的同义词指向了B1的对象,且B2拥有权限这个对象的权限,但是Oracle的bug导致了共享池中错误的SQL解析的存在,导致匹配这个SQL的访问报错。如果改变表名的大小写,或者添加别名,就不会报错。
现在成功了再现了这个错误,至此错误的解决过程全部结束。
来自 “ ITPUB博客 ” ,链接:http://blog.itpub.net/4227/viewspace-573387/,如需转载,请注明出处,否则将追究法律责任。
转载于:http://blog.itpub.net/4227/viewspace-573387/