我们正在将遗留应用程序从 IBM WebSphere 迁移到 OpenLiberty。某些功能使用 Oracle XSU 来执行数据库操作。
我通过对 java.sql.Connection 执行展开操作,成功获得了 Oracle 特定的连接。
尝试通过 XSU 插入数据时出现错误:
oracle.xml.sql.OracleXMLSQLException:com.ibm.ws.rsadapter.jdbc.v42.WSJdbc42PreparedStatement 无法转换为 oracle.jdbc.OraclePreparedStatement
我的服务器.xml:
获取并解开连接:
尝试使用 XSU 插入:
有人知道如何解决吗?
假设 ClassCastException 来自
oracle.xml.sql.dml.OracleXMLSave
(堆栈将确认这一点),您应该针对 Oracle 尝试直接转换为 oracle.jdbc.OraclePreparedStatement
而不是使用 unwrap
从它准备的语句中获取它。提供的连接。看起来您在代码中使用 unwrap
的做法是正确的,但 Oracle 代码需要在准备好的语句的代码中执行同样的操作。
假设问题是 Oracle 的 XSU 库没有解包PreparedStatements(感谢@njr),我找到了一个可行的解决方案。
通过 oracleConnection 构建代理,并将其传递给 XSU 库而不是实际的 oracleConnection:
OracleConnection oracleConnection = connection.unwrap(OracleConnection.class);
OracleConnection proxy = (OracleConnection) Proxy.newProxyInstance(
OracleConnection.class.getClassLoader(),
new Class<?>[]{OracleConnection.class},
new OracleConnectionInvocationHandler(oracleConnection));
OracleXMLSave sav = null;
try {
sav = getNewOracleXMLSave(proxy, tableName);
sav.setRowTag(rowDelimiter);
sav.setDateFormat("dd/MM/yyyy HH:mm:ss");
sav.insertXML(xsuXml);
这样,我可以拦截 XSU 库对prepareStatement 方法的调用,并在将对象返回到库之前进行解包。这是代理处理程序:
public class OracleConnectionInvocationHandler implements InvocationHandler {
private final OracleConnection target;
private SPELogger systemLog = null;
public OracleConnectionInvocationHandler(OracleConnection target) {
systemLog = AppLogger.getInstance();
this.target = target;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
if ("prepareStatement".equals(method.getName())) {
PreparedStatement preparedStatement = (PreparedStatement) method.invoke(target, args);
systemLog.logInfo(this, "Making PreparedStatement unwrap through OracleConnectionInvocationHandler");
return preparedStatement.unwrap(oracle.jdbc.OraclePreparedStatement.class);
}
return method.invoke(target, args);
}
}
与此同时,我仍在与 Oracle 联系,看看是否有 XSU 库可以正确处理此问题。但使用代理的解决方案效果很好。