Oracle 12c gbk字符集下解决特殊符号乱码问题

文章介绍了在已上线的项目中遇到特殊字符乱码问题的解决方案,主要涉及两种思路:更换字符集为UTF-8或使用NVARCHAR2字段类型。由于风险考虑,选择了后者,并在Mybatis中自定义typeHandler来处理。此外,还提到批量插入时的问题及其解决方法,以及一种通过16进制转换的替代方案,但此方案对某些字符可能产生新的乱码问题。
摘要由CSDN通过智能技术生成

项目已经在生产环境运行一段时间后,发现部分特殊符号存在乱码问题。经过查找资料后,大约有两种思路解决该问题,一是将字符集更换为UTF-8,二是将存储特殊字符的字段类型改为使用国家字符集中的NVARCHAR2。如前文所说,项目已经上线运行,更换字符集风险过大,于是采用第二种方式。

在调试的时候,遇到了无法批量插入的问题,可参考另一篇拙作解决:

Mybatis+Oracle批量插入方法总结_mybatis oracle批量插入_Chrisf Zhang的博客-CSDN博客

下面总结解决问题的两个思路,老规矩,将最终完美解决问题的方法记录在方式一,方式二记录思路及遇到的问题。

方式一:

 大致思路:数据库字段类型改为NVARCHAR2,mapper.xml中对应字段指定typeHandler,并为该类型重写typeHandler。

tips:

1 typeHandler是按照名称匹配的,mapper.xml中执行的类型与typeHandler的名称要对应;

2 原有字段直接把类型由“VARCHAR2”改为“NVARCHAR2”会报错,可以新加一个字段类型设置为“NVARCHAR2”,将原字段的数据复制到新字段,并改名称,最后把新字段的名称修改为原字段的即可。

数据库字段如下:

 mapper.xml中的修改如下:

 typeHandler如下:

package org.jeecg.modules.material.business.demand.handler;//package org.jeecg.modules.material.business.demand.handler;

import org.apache.ibatis.type.BaseTypeHandler;
import org.apache.ibatis.type.JdbcType;
import org.apache.ibatis.type.TypeException;

import java.sql.CallableStatement;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;

public class NVarcharTypeHandler extends BaseTypeHandler<String> {
   @Override
   public void setParameter(PreparedStatement ps, int i, String parameter, JdbcType jdbcType) throws SQLException {
       if(parameter == null) {
           if(jdbcType == null) {
               throw new TypeException("JDBC requires that the JdbcType must be specified for all nullable parameters.");
           }
           try {
               ps.setNull(i, jdbcType.TYPE_CODE);
           } catch (SQLException var7) {
               throw new TypeException("Error setting null for parameter #" + i + " with JdbcType " + jdbcType + " . " + "Try setting a different JdbcType for this parameter or a different jdbcTypeForNull configuration property. " + "Cause: " + var7, var7);
            }
        } else {
            try {
                this.setNonNullParameter(ps, i, parameter, jdbcType);
            } catch (Exception var6) {
                throw new TypeException("Error setting non null for parameter #" + i + " with JdbcType " + jdbcType + " . " + "Try setting a different JdbcType for this parameter or a different configuration property. " + "Cause: " + var6, var6);
            }
        }
    }


    /**
     * 这里使用setNString而不是setString
     * @param ps
     * @param i
     * @param parameter
     * @param jdbcType
     * @throws SQLException
     */
    @Override
    public void setNonNullParameter(PreparedStatement ps, int i, String parameter, JdbcType jdbcType) throws SQLException {
        ps.setNString(i, parameter);
    }

    @Override
    public String getNullableResult(ResultSet rs, String columnName) throws SQLException {
        return rs.getString(columnName);
    }

    @Override
    public String getNullableResult(ResultSet rs, int columnIndex) throws SQLException {
        return rs.getString(columnIndex);
    }

    @Override
    public String getNullableResult(CallableStatement cs, int columnIndex) throws SQLException {
        return cs.getString(columnIndex);
    }
}

方式二:

同样需要把数据库字段类型改为NVARCHAR2,收到参数后首先将特殊符号转换为16进制,存入数据库中时通过函数“utl_raw.cast_to_nvarchar2”进行转换,查询时无需特殊处理。

该方式仅能解决一部分特殊符号,例如ø等,一些没修改之前没乱码的特殊符号反而会产生乱码,例如φ等。

转换16进制代码如下:

    /**
     * 字符串转换
     * @param string
     * @return
     */
    public String unicodeEncode(String string) {
        char[] utfBytes = string.toCharArray();
        String unicodeBytes = "";
        for (int i = 0; i < utfBytes.length; i++) {
            String hexB = Integer.toHexString(utfBytes[i]);
            if (hexB.length() <= 2) {
                hexB = "00" + hexB;
            }
            unicodeBytes = unicodeBytes + hexB;
        }
        return unicodeBytes;
    }

mapper.xml中转换函数用法如下:

 

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值