将java.sql.Connection转换为oracle.jdbc.OracleConnection会导致编译错误

时间:2014-10-16 11:19:33

标签: oracle11g slick scala-2.10 bonecp

我想将java.sql.Connection投射到oracle.jdbc.OracleConnection,以便将ARRAY上的数据绑定到我的查询。

当我在scala 2.10,bonecp 0.8.0和slick 2.0.0上尝试以下内容时:

import com.jolbox.bonecp.ConnectionHandle
import oracle.jdbc.OracleConnection

def failsWithCompilationError() = {
  Database.forDataSource(ds).withDynTransaction {
    val connection = dynamicSession.conn.asInstanceOf[ConnectionHandle].getInternalConnection
    println(connection.unwrap(classOf[OracleConnection]))
    // When uncommenting following two lines a compilation error "error while loading AQMessage, class file '.../ojdbc6.jar(oracle/jdbc/aq/AQMessage.class)' is broken" will occur
    // val oracleConnection: OracleConnection = connection.unwrap(classOf[OracleConnection])
    // println(oracleConnection)
  }
}

并取消注释两行,并指定val类型OracleConnectionprintln编译失败

[error] error while loading AQMessage, class file '.../ojdbc6.jar(oracle/jdbc/aq/AQMessage.class)' is broken将会发生。

我已经通过从Oracle下载更新的版本来验证ojdbc6.jar不应该被破坏。

2 个答案:

答案 0 :(得分:1)

似乎问题出在Scala编译器上。

只要将依赖于oracle.jdbc.OracleConnection的功能嵌入到一个普通的旧Java类中,将其构建到一个单独的.jar中并与我的Scala代码链接就会开始滚动。

以下是我如何使用它:

OracleArray.java

package my.application.oracle.collections;

import oracle.jdbc.OracleConnection;
import oracle.jdbc.OraclePreparedStatement;
import oracle.sql.ARRAY;
import scala.Long;
import scala.Tuple2;

import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.List;

/*
Wraps usage of Oracle ARRAYs since casting java.sql.Connection to oracle.jdbc.Connection does not compile on Scala.
*/
public class OracleArray {
    public static List<Tuple2<Long, Long>> fetchAssetsByIds(List ids, Connection connection) throws SQLException {
        OracleConnection oracleConnection = (OracleConnection) connection;
        ARRAY oracleArray = oracleConnection.createARRAY("MY_ARRAY_SQL_TYPE", ids.toArray());
        String sql = "SELECT a.id, a.value" +
                "FROM ASSET a " +
                "WHERE a.id IN (SELECT COLUMN_VALUE FROM TABLE(?))";
        PreparedStatement statement = oracleConnection.prepareStatement(sql);
        try {
            OraclePreparedStatement oraclePreparedStatement = (OraclePreparedStatement) statement;
            oraclePreparedStatement.setArray(1, oracleArray);
            ResultSet resultSet = oraclePreparedStatement.executeQuery();
            try {
                ArrayList<Tuple2<Long, Long>> resultTuples = new ArrayList<>();
                while (resultSet.next()) {
                    long id = resultSet.getLong(1);
                    long value = resultSet.getLong(2);
                    resultTuples.add(new Tuple2(id, value));
                }
                return resultTuples;
            } finally {
                resultSet.close();
            }
        } finally {
            statement.close();
        }
    }
}

DataUser.scala

package my.application

import my.application.oracle.collections.OracleArray

import scala.slick.driver.JdbcDriver.backend.Database
import Database.dynamicSession
import com.jolbox.bonecp.ConnectionHandle

import java.sql.Connection
import collection.JavaConversions._

/*
  Uses BoneCP and Slick to connect to database and relays java.sql.Connection to
  OracleArray in order to run operations that use Oracle ARRAYs
*/
object DataUser {
    def doSomethingWithAssets(ids: Seq[Long]): Unit = {
        Database.forDataSource(ds).withDynTransaction {
            val connection: Connection = dynamicSession.conn.asInstanceOf[ConnectionHandle].getInternalConnection
            val assets: Seq[(Long, Long)] = OracleArray.fetchAssetsByIds(ids, connection)
            println(assets)
        }
    }
}

答案 1 :(得分:0)

不确定我的情况是否相关,但是使用Play框架,只有当logSql = false 时,这对我有用

db.withConnection { implicit c  =>
  val oracleConnection = c.unwrap(classOf[OracleConnection])
}

当我设置 logSql = true 时,我得到:

  

com.sun.proxy。$ Proxy17无法强制转换为oracle.jdbc.OracleConnection   java.lang.ClassCastException:com.sun.proxy。$ Proxy17无法强制转换为   oracle.jdbc.OracleConnection

因此logSql configuration的某些内容实际上会导致解包失败。不知道为什么。

我认为这可能与Hikari Connection Pool有关,但是您的连接池配置可能会导致类似的问题。