背景
最近在項(xiàng)目中遇到了之前同事埋下的大坑。項(xiàng)目用C3P0連接池伏嗜,從連接池直接獲取的連接在執(zhí)行oracle的存儲(chǔ)過(guò)程時(shí),會(huì)報(bào)java.lang.ClassCastException: com.mchange.v2.c3p0.impl.NewProxyCallableStatement cannot be cast to oracle.jdbc.OracleCallableStatement
的錯(cuò)誤窗怒,于是前人就沒(méi)有用連接池而是做了個(gè)直連來(lái)解決這個(gè)問(wèn)題淌哟。
解決過(guò)程
照常先是各種百度,谷歌報(bào)錯(cuò)信息惠豺,查到的原因都說(shuō)是存儲(chǔ)過(guò)程的游標(biāo)或者存儲(chǔ)過(guò)程的自定義參數(shù)類型的問(wèn)題银还。可是我們需要對(duì)接客戶的數(shù)據(jù)庫(kù)洁墙,總不能讓客戶改存儲(chǔ)過(guò)程吧蛹疯。既然直連可以使用,肯定是c3p0封裝的問(wèn)題热监。查了寫(xiě)資料苍苞,可以用到unwrap方法。但是看了下我們這邊的代碼狼纬,發(fā)現(xiàn)沒(méi)有具體實(shí)現(xiàn)unwrap方法羹呵。
最后查到了可以通過(guò)反射在底層的連接上來(lái)執(zhí)行非標(biāo)準(zhǔn)方法的API[1]
例子中使用C3P0ProxyConnection.RAW_CONNECTION
作為參數(shù),也就是在使用到connection
的時(shí)候才能完成疗琉。剛開(kāi)始看遍項(xiàng)目代碼改了幾個(gè)地方也沒(méi)成功冈欢,最后在網(wǎng)上發(fā)現(xiàn)了其他項(xiàng)目用的代碼,參考了一下盈简,他們是添加了一個(gè)方法凑耻,用來(lái)處理這個(gè)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 }
將以上代碼根據(jù)項(xiàng)目實(shí)際添加到項(xiàng)目中香浩,實(shí)現(xiàn)了c3p0獲取原生連接,解決了c3p0連接無(wú)法調(diào)用oracle的procedure的問(wèn)題臼勉。
參考文獻(xiàn)
[1] 數(shù)據(jù)庫(kù)連接池手冊(cè)
[2] SOS開(kāi)源項(xiàng)目源碼
[3] c3p0源碼