Oracle数据库SQLInput.readString()无法读取数据返回???问题排查求助
我之前也碰到过类似的Oracle自定义类型字符读取乱码的问题,结合你的情况,给你几个具体的排查方向:
检查目标数据库的字符集配置
字符集不匹配是这类乱码问题的重灾区。先对比正常数据库和异常数据库的字符集设置:- 执行SQL查询服务端字符集:
SELECT userenv('language') FROM DUAL;,看返回的语言和字符集(比如AMERICAN_AMERICA.AL32UTF8)是否和正常库一致。 - 检查JDBC连接的字符集参数:Oracle JDBC可以通过连接串指定字符集,比如添加
?oracle.net.ns.SessionData=NLS_LANG=AMERICAN_AMERICA.AL32UTF8,或者确保客户端的NLS_LANG环境变量和服务端匹配。 - 虽然你已经加了
orai18n.jar,但要确认这个jar的版本和JDBC驱动版本是否兼容,版本不匹配也可能导致字符转换失效。
- 执行SQL查询服务端字符集:
验证自定义类型字段的字符集属性
即使你定义的是VARCHAR2(50),不同数据库的类型属性可能有差异。可以查询自定义类型的元数据:SELECT ATTR_NAME, CHARACTER_SET_NAME FROM ALL_TYPE_ATTRS WHERE TYPE_NAME = 'MY_ROW' AND OWNER = '<你的用户>';对比正常库和异常库中
name字段的CHARACTER_SET_NAME是否一致,如果异常库的字符集是其他值(比如US7ASCII),就会导致读取乱码。尝试替换为readNString()方法
有时候Oracle JDBC对VARCHAR2的字符处理存在兼容性问题,你可以试试把代码中的readString()换成readNString():name = stream.readNString();readNString()是针对国家字符集的读取方法,但在某些字符集不匹配的场景下,反而能正确读取到VARCHAR2字段的内容。检查JDBC驱动版本与数据库版本的兼容性
确认三个数据库的Oracle版本是否一致?如果异常数据库是更高或更低的版本,而你用的是统一的JDBC驱动,可能存在兼容性问题。比如Oracle 19c的驱动在处理11g的某些字符集场景时会有差异,建议换成对应数据库版本的官方JDBC驱动(比如ojdbc8对应12c/19c,ojdbc10对应21c)。验证数据库中数据的实际存储
先排除数据本身的问题:在异常数据库中执行SELECT name, DUMP(name, 1016) FROM <你的表>,DUMP函数会返回字段的十六进制编码。如果编码是正常的(比如UTF-8字符对应正确的十六进制值),那问题出在JDBC读取转换;如果编码本身就不对,那可能是数据插入时的字符集问题。
内容的提问来源于stack exchange,提问作者Losmi

