文章转载自:http://www.blogjava.net/SpartaYew/archive/2011/05/18/350480.html
原作者:sparta-紫杉
一、开发及运行环境
eclipse3.4.2, weblogic8.12, oracle9.2, jdk1.4.2, struts1框架。
二、背景
今天在对项目代码review时,发现存在一个问题,在某一个Dao的代码里面,多了一个得到原生Connection的getConnection()方法,方法如下:
上述代码比较好理解,返回一个原生的Java Connection对象,但不免生出几点疑问:
1、整个项目采用Weblogic的连接池并通过DataSource获取连接,为何还要单独独立出一个连接代码来呢?
2、这个独立出的连接有什么具体的作用吗? 难道Weblogic的连接池的DataSource连接有一些无法完成的功能?
3、通过Weblogic的DataSource建立的连接与Java原生Connection有何区别?
下面给出Weblogic的连接池并通过DataSource获取连接的ConnectDB类:
带着上述问题,对代码进行分析,得到如下结果:
1、独立出的连接代码是单独为处理CLOB类型的字段数据内容而建立的,CLOB不能使用传统的insert into 方法插入,必须通过处理CLOB的专用方法。
2、通过ConnectDB.java中的getConnection()方法虽然也能得到Java原生的Connection,但是在存取CLOB的字段时,总是出现“ClassCastException”错误。
出错代码如下:
oracle.sql.CLOB clob = ((OracleResultSet) rss).getCLOB(1);
原因是与Weblogic中的对Clob处理的代码有转型上的错误。
3、经过分析发现,应该就是由于使用通过ConnectDB.java建立的Weblogic的DataSource连接池无法处理OracleResultSet类型的CLOB数据。
为了验证自己的分析,将由ConnectDB.java中的getConnection()方法换为Dao代码中的getConnection(),
oracle.sql.CLOB clob = ((OracleResultSet) rss).getCLOB(1);代码是完全可以正常运行的。
所以,开发人员在Weblogic的连接池之外,又重新建立了一个Java原生的Connection,用以专门处理CLOB的字段内容,似乎是无奈之举。
但不难发现,上述代码有下面的几个缺点:
1、在项目中建立两套连接(并且两套连接指向同一个数据库)是非常不规范的处理方式,况且其中之一并非Weblogic管理的连接池,而是一个Java原生Connection,不能利用Weblogic的连接池的优点。
2、管理两套连接除了带来管理上的困难,而且带来编码上的麻烦。
3、使用Java原生Connection是硬编码方式,必须在不同的数据库连接环境(数据库连接的字串、SID、IP等)中硬编码切换,应用网和本地来回切换,若不注意,则会造成错误。
通过以上的缺点,笔者认为应该充分利用Weblogic的DataSource数据源及连接池,在整个项目中仅保留一套Connection,因此针对该问题进行研究,
使Weblogic的DataSource数据源及连接池也能够连接正确处理CLOB。
三、分析研究
其实在ConnectDB.java中通过Weblogic的DataSource生成的Connection和Java原生Connection本质上是相同的,处理CLOB出错的原因并非在Connection,
而在于通过数据库连接生成的结果集(ResultSet),Java原生ResultSet和Weblogic对于ResultSet处理上是不同的,这里就是产生CastException的原因,
这也是对oracle.sql.CLOB clob = ((OracleResultSet) rss).getCLOB(1);这行代码进行研究后得出的结果。
weblogic服务器中,在通过datasourse获取connection,CLOB字段取出来的就不是oracle.sql.CLOB类型,而是weblogic封装过的OracleThinClob类型,
执行CLOB oCLOB = (CLOB) rs.getClob(1);所以cast的时候肯定会出错,出现ClassCaseException异常。
换言之,通过Weblogic的DataSource连接获得的CLOB的ResultSet是不能转型为java原生CLOB的ResultSet的。 也就是说,除了Java原生ResultSet之外,
每个应用服务器(Tomcat,weblogic,jboss等)都应该有自己处理CLOB型ResultSet的方式方法,并且不能通用(至少不可以转型)。
目前,笔者见到的有三种处理CLOB型ResultSet的方法:
1、Java原生ResultSet,通常的代码为: oracle.sql.CLOB clob = ((OracleResultSet) rss).getCLOB(1);
2、Tomcat处理CLOB型ResultSet:须将lib下的classes12.jar(oracle包)删除,但程序不需要改动。
3、通过Weblogic的DataSource获得的连接池,可采用如下代码:
weblogic.jdbc.vendor.oracle.OracleThinClob clob = (weblogic.jdbc.vendor.oracle.OracleThinClob)rss.getClob(1);
当然,要获得weblogic.jdbc.vendor.oracle.OracleThinClob接口还必须将D:\bea812\weblogic81\server\lib下的weblogic.jar
拷贝到项目的E:\eclipse3.4.2\workspace\sykf\webapp\WEB-INF\lib下,才能正常使用。
鉴于本项目使用Weblogic做应用服务器,并且需要充分利用Weblogic的连接池建立的数据库连接,因此,笔者采用第三种方式来解决这个问题,也就是说将
D:\bea812\weblogic81\server\lib下的weblogic.jar拷贝到项目的E:\eclipse3.4.2\workspace\sykf\webapp\WEB-INF\lib下。
四、先为weblogic.jar减减肥吧
要知道,从D:\bea812\weblogic81\server\lib下的weblogic.jar获得的该jar容量是非常大的,达36M之多,这么大的jar包放到项目lib下有些笨拙,这个不要紧,可以对之进行减肥,将里面不需要的包删除掉就可以了,具体步骤如下:
1)、解压该jar包,成为一个文件夹。
2)、将里面除jdbc之外的包全部删除。
3)、重新压缩成jar包。
笔者通过上述处理之后,成功将36M体积的Weblogic.jar减肥为713K。
在这里可能有读者会有如下疑问:
你的lib下有weblogic.jar包,并且Weblogic下也有weblogic.jar包,并且两个jar中包含的jdbc.vendor.oracle.OracleThinclob相同,两者不会冲突吗?
这个不必担心,因为包名类名虽然都相同,即使jvm也没法区分,那JVM在处理时就只有第一个包被引入(在classpath路径下排在前面的包),
第二个包会在classloader加载类时判断重复而忽略。
五、下面给出Weblogic的Datasource连接的Resultset写CLOB字段的代码
写方法:
读方法:
六、另外再给出Tomcat的连接池处理ResultSet的CLOB字段的方法
代码与Java原生ResultSet写CLOB型字段的代码一样,但是需要注意,要将项目的lib文件夹下的classes12.jar删除才不会出现ClassCastException错误。