ITPub博客

首页 > Linux操作系统 > Linux操作系统 > BEA的Oracle JDBC驱动与Oracle的JDBC驱动区别如此之大,请谨慎选择、使用和调整!

BEA的Oracle JDBC驱动与Oracle的JDBC驱动区别如此之大,请谨慎选择、使用和调整!

原创 Linux操作系统 作者:尛样儿 时间:2011-04-24 17:22:15 0 删除 编辑

下面我对问题的发现,对疑问的测试,最后说明了什么问题做一个详细的描述。

发现问题的由来:
公司的某个运行的项目,数据库是Oracle RAC,应用服务器是Weblogic,Weblogic的连接池使用的是BEA JDBC Thin驱动。
如下图所示:

使用BEA的驱动不能配置RAC的负载均衡,只能连接到RAC的某个节点,一旦这个节点出现故障,将影响整个系统的使用,这样就不能体现出系统的高可用性。为了避免Oracle数据库单节点故障给应用系统带来的影响必须在连接池上实现负载均衡,一旦发现单节点故障,Weblogic可以通过负载均衡机制重新连接到RAC的其他节点。
故做出如下调整:
1.将BEA JDBC THIN驱动更换为Oracle JDBC Thin驱动,如下图所示:

2.将连接字符串修改为:
jdbc:oracle:thin:@(DESCRIPTION =(FAILOVER=on)(LOAD_BALANCE=yes)(ADDRESS_LIST =(ADDRESS = (PROTOCOL = TCP)(HOST = bwgl_db1-vip)(PORT = 1521))(ADDRESS = (PROTOCOL = TCP)(HOST = bwgl_db2-vip)(PORT = 1521)))(CONNECT_DATA =(SERVER = DEDICATED)(SERVICE_NAME = FZFWDB)))
这样Weblogic的连接池就可以实现负载均衡,在RAC出现单节点故障的情况下也能确保系统能够重新创建连接成功。

当修改成功之后出现如下问题:
系统在访问的时候总会报"ORA-01843 无效月份"的错误,导致系统无法正常的使用。


思考:
在数据库上出现这种错误,一般是由于NLS_LANG环境变量没设置,或设置不正确的问题导致的,例如,数据库保存的时间为:12-JUN-2010 表示2010年6月12日,服务器端的语言是AMERICAN,如果客户端的语言是CHINESE的话那么表示的结果是12-六月-2010,这样就会导致无效月份报错的出现。解决这个的办法是在客户端设置NLS_LANG环境变量NLS_LANG=AMERICAN_AMERICA.xxx这样将客户端和服务器端的语言统一就可以避免无效月份的报错,可以参考我的另一篇文章:
http://space.itpub.net/23135684/viewspace-628044 
但通过对客户端、服务器端NLS_LANG的设置和测试发现并不是由上面的原因造成的。经过对代码的检查发现问题的所在:
在发生某项业务的时候,系统会向数据库插入一个时间戳(数据库类型timestamp),由于在代码中生成的SQL绑定的时间使用+号来绑定,这样就将时间转换成了字符串。通过打印就可以看到类似下面的SQL被传递到数据库来执行:
insert into d(d) values ('2010-12-12 23:23:23');
我们将java后台打印的这条SQL语句拿到数据库执行,就报了ORA-01843错误。这样显然是不可以执行的(加上to_date或者to_timestamp就可以正常执行),为什么之前没有报错喃?中间做过什么操作?why?中间只将BEA的JDBC Thin驱动修改为了Oracle JDBC Thin驱动,难道事驱动的问题?难道是驱动对插入时间的字符串有不同的解析?带着这些疑问做了如下实验:
(由于笔者很久不写Java代码了,写得不好请看着包涵)。

首先我用Eclipse+Weblogic 9.2+Oracle 10.2.0.4搭建了一个测试环境。由于BEA JDBC Thin驱动必须在Webglogic的环境下才能使用,所以必须创建J2EE应用才能测试。
Oracle Jdbc Thin驱动测试:
我在创建的J2EE应用中创建了一个名为myjsp.jsp的jsp文件,在里面加入了如下代码:
<%
java.sql.Connection conn;
java.sql.Statement stmt = null;
java.sql.ResultSet rs = null;

Class.forName("oracle.jdbc.driver.OracleDriver").newInstance();
String url="jdbc:oracle:thin:@192.168.193.128:1521:sdlndata";

String uid="test";
String pwd="test";
conn= java.sql.DriverManager.getConnection(url,uid,pwd);
stmt=conn.createStatement();
stmt.executeQuery("insert into d values ('2010-12-12 23:11:11')");
conn.commit();
stmt.close();
conn.close();
%>
通过将这个jsp页面对应的应用部署到Weblogic下面,通过
http://localhost:7001/mysjp.jsp访问应用。得到ORA-01843:无效月份报错。其实不管是Oracle JDBC Thin驱动还是Oracle 本地服务器名连接都不不允许这样写的,只有在时间戳上加上to_date或者to_timestamp才能保证正常的插入,例如:
insert into d values (to_timestamp('2010-12-12 23:11:11','yyyy-mm-dd hh24:mi:ss'));

BEA JDBC Thin驱动测试:
将myjsp.jsp原有的<%%>包涵的代码修改为:
<%
java.sql.Connection conn;
java.sql.Statement stmt = null;
java.sql.ResultSet rs = null;

Class.forName("weblogic.jdbc.oracle.OracleDriver").newInstance();
String url="jdbc:bea:oracle://192.168.193.128:1521;sid=sdlndata";
String uid="test";
String pwd="test";
conn= java.sql.DriverManager.getConnection(url,uid,pwd);
stmt=conn.createStatement();
rs=stmt.executeQuery("insert into d values ('2010-12-12 23:11:11')");
conn.commit();
stmt.close();
conn.close();
%>

修改完后重新发布、更新war包,然后再次通过
http://localhost:7001/myjsp.jsp来访问这个地址让它调用这段代码。令我意想不到的是居然没报错,然后查询数据库的D表,数据正常被插入!!!Oh 我的天,居然有这种事情,驱动的更换会带来这么大的差异!!!

同样都是执行insert into d values ('2010-12-12 23:11:11')语句,使用Oracle JDBC Thin连接的会话就无法执行,会出现ORA-01843错误,使用BEA JDBC Thin驱动就可以正常执行插入。

总结:
对于Oracle来说,不同厂商的驱动在实现对时间字符串的处理是不同的。我们一定要注意到这点,在开发、更换驱动的时候都要谨慎,避免驱动处理的不同给系统带来不必要的麻烦。对于连接Oracle数据库来说,推荐使用Oracle的驱动,因为Oracle的驱动具备某些特性能为连接Oracle数据库带来某些高可用性的效果,比如负载均衡连接等。其次在开发的时候应该养成好的习惯:
1.使用绑定变量,如果在这个案例中,使用绑定变量的话,传入的将是timestamp对象,而不是字符串,或许就不会出现这种错误。
2.必要时一定要使用合适的函数,来减少强制转换等工作,这样也可以避免出现这种问题。
通过以上2点才能保证在系统迁移,驱动更换等情况下,系统保持强壮性,避免出现驱动,系统的兼容性问题。


特此将昨晚的问题,以及今日的测试过程记下以备查阅。

2011-4-24 17-26-38.jpg

2011-4-24 17-30-49.jpg

来自 “ ITPUB博客 ” ,链接:http://blog.itpub.net/23135684/viewspace-693310/,如需转载,请注明出处,否则将追究法律责任。

请登录后发表评论 登录
全部评论
Oracle数据库管理员,Oracle数据库系统构架员;2012年7月出版《构建最高可用Oracle数据库系统:Oracle 11gR2 RAC管理、维护与性能优化》一书;Oracle 10g OCM。

注册时间:2010-01-05

  • 博文量
    483
  • 访问量
    5353994