背景
最近在项目中遇到了之前同事埋下的大坑。项目用C3P0连接池,从连接池直接获取的连接在执行oracle的存储过程时,会报java.lang.ClassCastException: com.mchange.v2.c3p0.impl.NewProxyCallableStatement cannot be cast to oracle.jdbc.OracleCallableStatement
的错误,于是前人就没有用连接池而是做了个直连来解决这个问题。
解决过程
照常先是各种百度,谷歌报错信息,查到的原因都说是存储过程的游标或者存储过程的自定义参数类型的问题。可是我们需要对接客户的数据库,总不能让客户改存储过程吧。既然直连可以使用,肯定是c3p0封装的问题。查了写资料,可以用到unwrap方法。但是看了下我们这边的代码,发现没有具体实现unwrap方法。
最后查到了可以通过反射在底层的连接上来执行非标准方法的API[1]
原生连接使用例子中使用C3P0ProxyConnection.RAW_CONNECTION
作为参数,也就是在使用到connection
的时候才能完成。刚开始看遍项目代码改了几个地方也没成功,最后在网上发现了其他项目用的代码,参考了一下,他们是添加了一个方法,用来处理这个connection
,非常巧妙。
public static Connection getRawConnection(Connection con) { return con; }
C3P0ProxyConnection cpCon = (C3P0ProxyConnection) conn; Connection unwrappedCon = null; try { Method rawConnectionMethod = getClass().getMethod("getRawConnection", new Class[] { Connection.class }); unwrappedCon = (Connection) cpCon.rawConnectionOperation(rawConnectionMethod, null, new Object[] { C3P0ProxyConnection.RAW_CONNECTION }); } catch (Exception ex) { //do something }
将以上代码根据项目实际添加到项目中,实现了c3p0获取原生连接,解决了c3p0连接无法调用oracle的procedure的问题。
网友评论