从WebSphere迁移到OpenLiberty时Oracle XSU插入数据遇ClassCastException
我们正将遗留应用从IBM WebSphere迁移至OpenLiberty,部分功能依赖Oracle XSU执行数据库操作。已通过java.sql.Connection.unwrap()获取到Oracle专属连接,但调用XSU的insertXML()时触发以下错误:
oracle.xml.sql.OracleXMLSQLException: com.ibm.ws.rsadapter.jdbc.v42.WSJdbc42PreparedStatement cannot be cast to oracle.jdbc.OraclePreparedStatement
相关配置与代码
server.xml配置
<library id="jdbcLib"> <fileset dir="C:\Users\uC260112\.m2\repository\com\oracle\ojdbc6\11.2.0.1.0"/> </library> <dataSource id="gcmsXAWIPDS" jndiName="jdbc/gcmsXAWIPDS" type="javax.sql.XADataSource"> <jdbcDriver javax.sql.XADataSource="oracle.jdbc.xa.client.OracleXADataSource" libraryRef="jdbcLib"/> <properties.oracle URL="jdbc:oracle:thin:@c588cwegcmd03.int.xxxx.com:1521/xxxxx.int.xxxxx.com" password="xxxxxx" user="xxxxxx"/> <connectionManager maxPoolSize="100" minPoolSize="1"/> </dataSource> <enterpriseApplication id="xxxxx" location="xxxxx-1.0.ear" name="xxxxx"> <classloader commonLibraryRef="jdbcLib"/> </enterpriseApplication>
获取Oracle连接的代码
conId = myXAPool.obtainConnection(null, null); Connection connection = myXAPool.getConnection(conId); OracleConnection oracleConnection = connection.unwrap(OracleConnection.class);
XSU插入数据的代码
OracleXMLSave sav = null; try { sav = getNewOracleXMLSave(oracleConnection, tableName); sav.setRowTag(rowDelimiter); sav.setDateFormat("dd/MM/yyyy HH:mm:ss"); sav.insertXML(xsuXml); // 异常触发点 } catch (Exception ex) { // 异常处理 }
这个问题的核心是OpenLiberty的JDBC代理机制仍在包装PreparedStatement对象,导致XSU无法将其转换为Oracle专属的OraclePreparedStatement。可以通过以下步骤解决:
禁用PreparedStatement缓存与包装
修改server.xml中的数据源配置,添加两个关键配置:- 在
<properties.oracle>中加入wrapPreparedStatements="false",禁用Oracle驱动自身的语句包装 - 在
<connectionManager>中设置prepareStatementCacheSize="0",关闭OpenLiberty的PreparedStatement缓存(避免代理包装)
修改后的数据源配置如下:
<dataSource id="gcmsXAWIPDS" jndiName="jdbc/gcmsXAWIPDS" type="javax.sql.XADataSource"> <jdbcDriver javax.sql.XADataSource="oracle.jdbc.xa.client.OracleXADataSource" libraryRef="jdbcLib"/> <properties.oracle URL="jdbc:oracle:thin:@c588cwegcmd03.int.xxxx.com:1521/xxxxx.int.xxxxx.com" password="xxxxxx" user="xxxxxx" wrapPreparedStatements="false"/> <connectionManager maxPoolSize="100" minPoolSize="1" prepareStatementCacheSize="0"/> </dataSource>- 在
验证unwrap后的连接有效性
在代码中打印oracleConnection的类名,确认已拿到Oracle原生连接而非OpenLiberty代理:System.out.println("OracleConnection class: " + oracleConnection.getClass().getName());正常输出应为
oracle.jdbc.driver.T4CConnection或Oracle 11g对应的原生连接类,而非以com.ibm.ws.rsadapter开头的代理类。确保XSU与JDBC版本兼容
检查Oracle XSU的版本是否与ojdbc6(11.2.0.1.0)匹配,建议使用Oracle 11gR2版本的XSU包,避免版本不兼容导致的类型转换问题。检查XSU实例创建逻辑
确认getNewOracleXMLSave方法是通过传入的OracleConnection创建XSU实例,例如使用标准构造函数:private OracleXMLSave getNewOracleXMLSave(OracleConnection conn, String tableName) throws SQLException { return new OracleXMLSaveImpl(conn, tableName); }避免在方法内部重新获取连接,导致使用未unwrap的代理连接。
内容的提问来源于stack exchange,提问作者israelsm

