如何使用Scala连接Oracle读取大量数据及字符集报错问题求助
问题排查
你的错误分为两类:字符集依赖缺失,以及代码本身的逻辑错误。
1. 字符集依赖问题
异常提示已经明确说明:你连接的Oracle库使用了AR8MSWIN1256(阿拉伯语Windows编码)字符集,Oracle官方JDBC默认只包含常用字符集支持,这类小众字符集需要额外引入orai18n.jar扩展包才能正常解析。
2. 代码逻辑错误
- 你将创建函数的DDL语句和查询语句拼接在一起执行,
executeQuery方法仅支持执行单条查询语句,无法同时执行DDL+查询逻辑 - ResultSet遍历顺序错误:当前使用
do-while会先尝试读取第一行数据再判断是否存在下一行,首次读取就会抛出空结果异常 - 数据库连接、Statement、ResultSet使用完成后未主动释放,会造成连接资源泄漏
- 直接拼接SQL存在SQL注入风险,且拼接过程容易出现语法错误
修复方案
1. 补充字符集依赖
根据你使用的构建工具添加对应依赖,注意orai18n的版本必须和你当前使用的ojdbc驱动版本完全一致:
- SBT配置:
libraryDependencies += "com.oracle.database.nls" % "orai18n" % "你的ojdbc版本号"
- 无构建工具的项目,直接下载对应版本的
orai18n.jar放入项目依赖目录,添加到运行时classpath即可。
2. 修复代码逻辑
建议直接将自定义函数的逻辑整合到查询语句中,无需每次执行都创建临时函数,同时优化资源管理和遍历逻辑:
import java.sql.Connection import oracle.jdbc.pool.OracleDataSource import scala.util.Using object ReadTable extends App { val num = 4 val tableName = "table" val colName = "col" val oracleUser = "orcl" val oraclePassword = "******" val oracleURL = "jdbc:oracle:thin:@//x.x.x.x:1521/orcldb" // 提前初始化数据源,无需每次调用方法都创建 private val ods = new OracleDataSource() ods.setUser(oracleUser) ods.setURL(oracleURL) ods.setPassword(oraclePassword) def readData(groupId: Int): Unit = { // 函数逻辑直接写到查询条件中,用?占位符避免注入 val query = s""" select * from $tableName where MOD(TO_NUMBER(substr($colName, -LEAST(2, LENGTH($colName)))), $num) = ? """ // 使用Using自动管理资源,无需手动关闭 Using.Manager { use => val con = use(ods.getConnection()) val statement = use(con.prepareStatement(query)) statement.setInt(1, groupId) statement.setFetchSize(1000) val resultSet = use(statement.executeQuery()) while (resultSet.next()) { val cst = resultSet.getString("cst") val name = resultSet.getString("name") println(s"cst = $cst, name = $name") } }.recover { case e: Exception => e.printStackTrace() } } readData(1) }
如果你确实需要创建自定义函数,单独用statement.execute(ddl语句)执行创建逻辑即可,不要和查询语句拼接。
内容的提问来源于stack exchange,提问作者M_Gh
相关产品推荐
相关产品推荐

