记一次解决oracle乱码问题

背景:公司做的医院His项目,而His项目用的都是Oracle,公司上项目的时候字符集配的是AMERICAN_AMERICA.US7ASCII中字符集,最近公司要上一个第三方报表系统,起初我在开发环境配置好报表后,一切正常并没有乱码,然而当我上线部署的时候却发现乱码了,研究一番后得出结论不支持编码,没有源码需要另辟蹊径解决问题。

思路一:利用Java Agent 注入转码代码,使其在执行sql时进行转码。

   我们自己的项目在上的时候其实也 出现了乱码,最后我利用alibaba Druid的转码功能才避免了乱码,配置如下:

spring:
  datasource:
    druid:
      driver-class-name: oracle.jdbc.driver.OracleDriver
      url: jdbc:wrap-jdbc:filters=encoding:jdbc:oracle:thin:@192.168.1.3:1521

  根据这个思路我想是不是可以把这个属性注入到报表系统里,刚好报表系统也是java项目,于是我又找到一篇文章的描述,通过如下方式来转码:

 String sql = "select code,fee_type from t_fee_type";

        Properties props = new Properties();
        props.setProperty("serverEncoding","ISO-8859-1");
        props.setProperty("clientEncoding","GBK");
        props.put("user", DBUSER);
        props.put("password", DBPASS);
        Connection conn = (Connection) DriverManager.getConnection(DBURL,props);
        PreparedStatement ps = (PreparedStatement)conn.prepareStatement(sql, ResultSet.TYPE_SCROLL_SENSITIVE);
        //Statement stmt = conn.createStatement();
        //ps.setNString(1,"病程记录");
        ResultSet rs = ps.executeQuery();
        List<Map<String, Object>> mapList = print(rs);
        for (Map<String, Object> objectMap : mapList) {
            System.out.println(objectMap);
        }
        //关闭资源
        if(rs!=null){rs.close();}
        if(ps!=null){ps.close();}
        if(conn!=null){conn.close();}
    }

那我是不是可以把这里的Properties属性注入报表里面从而达到转码的作用了,说干就干,反编译了报表系统,大致看了下源码,找到注入点位置,写完注入代码,一执行,报jdbcUrl不支持这种写法的错,换个方法绕过jdbcUrl检查再试还是报错(具体是什么错忘记了),看来此路不通,还得另外再想办法

思路二:利用oracle client 实现转码

公司同事用C#的比较多,具一个有经验的同事介绍他如果遇到编码问题搞不定的会用到OleDbConnection的方式连接oracle,原理就是本地安装一个oracle客户端程序通过与安装的oracle客户端交互实现oracle通讯,而oracle 客户端只要通过配置环境编码就能解决乱码问题,顺着这个思路查资料了解到java有个oci的形式也能这样实现,说干就干,于是就有了第二个解决思路。

第一步安装oracle client,找了个linux 安装oracle client 教程,先下载oracle client 的几个包,我用的是rpm形式

libaio-0.3.109-13.el7.x86_64.rpm

oracle-instantclient-basic-21.14.0.0.0-1.x86_64.rpm

oracle-instantclient-devel-21.14.0.0.0-1.x86_64.rpm

oracle-instantclient-sqlplus-21.14.0.0.0-1.x86_64.rpm

配置tnsnames.ora

test=
  (DESCRIPTION =
    (ADDRESS_LIST =
      (ADDRESS = (PROTOCOL = TCP)(HOST = 192.168.2.181)(PORT = 1521))
    )
    (CONNECT_DATA =
      (SERVICE_NAME = ORCL)
    )
  )

设置环境变量

 vi ~/.bashrc

export  ORACLE_HOME=/usr/lib/oracle/21/client64
export  TNS_ADMIN=$ORACLE_HOME/network/admin
export  LD_LIBRARY_PATH=$ORACLE_HOME/lib
export  PATH=$ORACLE_HOME/bin:$PATH
export  NLS_LANG=AMERICAN_AMERICA.ZHS16GBK

source ~/.bashrc

配置完后再在报表系统更改连接url,改成jdbc:oracle:oci:@test,修改后发布,结果还是连不上报错java.lang.UnsatisfiedLinkError: no ocijdbc21 in java.library.path,又是一顿疯狂的查资料,有个答案说对了,java要链接到oracle client的lib下才能读到oracle client的文件,于是tomcat里添加配置 -Djava.library.path=/usr/lib/oracle/21/client64/lib,再次运行,还是报错,这次报的是Incompatible version of libocijdbc[Jdbc:112040, Jdbc-OCI:112030,这一看就是oracle_client的驱动与java的版本不对,于是我第一时间想到的是卸掉oracle client,装了一个低版本的oracle client (11版本),又一次上线运行,结果还是不行,此时我 的心态有点快不行了,喘口气,喝口水平复下心情,认真分析了下报错信息:java.lang.UnsatisfiedLinkError: no ocijdbc21 in java.library.path,我明明配了11的版本怎么说找不到12的版本,问题应该就出在ojdbc驱动上,ojdbc驱动太高,要的12我给的11,所以应该是驱动问题,那如何能找到合适的驱动呢?又是一顿资料查找,但是没啥结果,于是我又看了下oracle client的项目结构,我发现lib下有个ojdbc.jar,那我是不是可以用这个驱动试下,我于是把这个驱动替换成原来的驱动,上线运行,不报找不到驱动的错误了,但是又报另外的错误TNS:could not resolve the connect identifier specified,这是找不到oracle服务啊,那肯定跟配置有关,于是又一顿配置检查,环境变量检查,发现都没问题,错误依旧,此时心态又有点上来了,又稍微平复下心情,看了下oracle client 的目录结构,发现在lib下有个network/admin的目录,里面有个readme,大致意思是这里是默认配置服务的地方,那我是不是可以把配置放这里试下,死马当活马医呗,把配置挪过来,上线一运行,不报错了,能正常 访问数据库了。高兴的是oci终于连上了,问题是乱码依旧,进去sqlplus查数据也是乱码,那剩下的就是尝试改oracle client的编码解决乱码了,改了好几个编码还是乱码,最后只好请求报表官方,官方给出了一个oracle版本与驱动版本匹配介绍链接,意思是不同的oracle 版本要匹配相对应的驱动,按官方的介绍替换驱动,最后乱码解决了,其实一开始就咨询官方找到替换驱动的解决方案,自己不用折腾这么久了,虽然写出来可能就这么几百上千字,但是整整花了三四天才解决这个问题,真是坑啊。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值