AIGC标识 数据库字符集处理

背景:

老数据库(oracle 10g)存储数据,字符集:AMERICAN_AMERICA.US7ASCII

系统也是使用的老模式,需要在数据库中插入和读取数据

最终发现只需要处理中文,数字和英文是不需要处理的!

网上或者是AI的话,都是建议换掉,因为数据库版本和字符集都太陈旧了,但是没有办法,不能换。只能处理转换

1.插入数据

/** 存入数据库前转码 */
    public static String chineseEncode(String parm) throws UnsupportedEncodingException {
        if(parm==null || parm.isEmpty()){
            return new String("");
        }
        return new String(parm.getBytes("gbk"), "ISO-8859-1");
    }

2.查询取出

/**
     * 将字节数组按 GBK 字符集解码为 Java String。
     * 私有工具方法,被上述三个 getNullableResult 方法复用。
     *
     * @param bytes 数据库返回的字节数组(可能为 null)
     * @return 解码后的字符串;若输入为 null,则返回 null
     * @throws SQLException 如果 GBK 解码失败(如字节序列不符合 GBK 规范)
     */
    private String convertFromBytes(byte[] bytes) throws SQLException {
        if (bytes == null) {
            return null;
        }
        try {
            // 使用 GBK 字符集将字节数组转换为字符串
            return new String(bytes, GBK);
        } catch (UnsupportedEncodingException e) {
            log.error("查询时转码异常:",e);
            // 理论上 GBK 总是可用,但此处仍做异常处理并包装为 SQLException
            throw new SQLException("GBK decoding failed", e);
        }
    }

3.最终使用

  3.1 字段上增加注解

  这里使用的mybatis plus的注解

    /** 卖方名称 */
    @Excel(name = "卖方名称")
    @ApiModelProperty("卖方名称")
    @TableField(typeHandler = GbkBlobTypeHandler.class)
    private String dwmc;

  3.2 BaseTypeHandler处理器实现,代码AI生成

package com.luan.avs.handle;

import lombok.extern.slf4j.Slf4j;
import org.apache.ibatis.type.BaseTypeHandler;
import org.apache.ibatis.type.JdbcType;
import org.apache.ibatis.type.MappedJdbcTypes;
import org.apache.ibatis.type.MappedTypes;

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

/**
 * 自定义 MyBatis TypeHandler,用于处理 Java String 类型与数据库 BLOB/VARBINARY 类型之间的转换,
 * 转换时使用 GBK 字符集进行编码/解码。
 * <p>
 * 适用场景:
 * - 对接遗留系统或第三方数据库,其中文本字段以 GBK 编码的字节形式存储在 BLOB/RAW 类型列中。
 * - 需要确保读取和写入时字符编码一致性,避免乱码问题。
 * <p>
 * 注意:该 TypeHandler 会全局影响所有使用该字段的查询和插入操作,
 * 如果只需要对特定数据源生效,建议配合独立的 SqlSessionFactory 使用。
 *
 * @author yxg
 * @since 2026-03-24
 */
@Slf4j
@MappedTypes(String.class)          // 指定处理的 Java 类型为 String
@MappedJdbcTypes({JdbcType.VARCHAR, JdbcType.BLOB, JdbcType.VARBINARY, JdbcType.NVARCHAR})
public class GbkBlobTypeHandler extends BaseTypeHandler<String> {

    /**
     * GBK 字符集名称常量。
     * GBK 是中文 Windows 系统常用的扩展字符集,支持简体中文。
     */
    private static final String GBK = "GBK";

    /**
     * 设置非空参数:将 Java String 转换为 GBK 编码的字节数组,并设置到 PreparedStatement 中。
     *
     * @param ps        PreparedStatement 对象
     * @param i         参数索引(从 1 开始)
     * @param parameter 要设置的 Java String 参数值(非 null)
     * @param jdbcType  参数的 JDBC 类型(由 MyBatis 自动推断,此处未直接使用)
     * @throws SQLException 如果发生数据库访问错误,或 GBK 编码转换失败(包装为 SQLException)
     */
    @Override
    public void setNonNullParameter(PreparedStatement ps, int i, String parameter, JdbcType jdbcType) throws SQLException {
        try {
            // 将 Java String 按 GBK 编码转换为字节数组
            String str = chineseEncode(parameter);
            // 将字节数组设置到 PreparedStatement 中(对应数据库 BLOB/VARBINARY 类型)
            ps.setString(i, str);
        } catch (UnsupportedEncodingException e) {
            log.error("插入时转码异常:",e);
            // 理论上 GBK 字符集在所有 Java 平台均受支持,但为了健壮性仍进行异常处理
            throw new SQLException("GBK encoding not supported when setting parameter at index " + i, e);
        }
    }
    /** 存入数据库前转码 */
    public static String chineseEncode(String parm) throws UnsupportedEncodingException {
        if(parm==null || parm.isEmpty()){
            return new String("");
        }
        return new String(parm.getBytes("gbk"), "ISO-8859-1");
    }

    /**
     * 从 ResultSet 中根据列名获取值,并将数据库中的字节数组按 GBK 解码为 Java String。
     *
     * @param rs         ResultSet 对象
     * @param columnName 列名
     * @return 解码后的 Java String;如果数据库值为 null,则返回 null
     * @throws SQLException 如果发生数据库访问错误,或 GBK 解码失败(包装为 SQLException)
     */
    @Override
    public String getNullableResult(ResultSet rs, String columnName) throws SQLException {
        byte[] bytes = rs.getBytes(columnName);
        return convertFromBytes(bytes);
    }

    /**
     * 从 ResultSet 中根据列索引获取值,并将数据库中的字节数组按 GBK 解码为 Java String。
     *
     * @param rs          ResultSet 对象
     * @param columnIndex 列索引(从 1 开始)
     * @return 解码后的 Java String;如果数据库值为 null,则返回 null
     * @throws SQLException 如果发生数据库访问错误,或 GBK 解码失败(包装为 SQLException)
     */
    @Override
    public String getNullableResult(ResultSet rs, int columnIndex) throws SQLException {
        byte[] bytes = rs.getBytes(columnIndex);
        return convertFromBytes(bytes);
    }

    /**
     * 从 CallableStatement 中根据列索引获取值(用于存储过程输出参数),
     * 并将数据库中的字节数组按 GBK 解码为 Java String。
     *
     * @param cs          CallableStatement 对象
     * @param columnIndex 列索引(从 1 开始)
     * @return 解码后的 Java String;如果数据库值为 null,则返回 null
     * @throws SQLException 如果发生数据库访问错误,或 GBK 解码失败(包装为 SQLException)
     */
    @Override
    public String getNullableResult(CallableStatement cs, int columnIndex) throws SQLException {
        byte[] bytes = cs.getBytes(columnIndex);
        return convertFromBytes(bytes);
    }

    /**
     * 将字节数组按 GBK 字符集解码为 Java String。
     * 私有工具方法,被上述三个 getNullableResult 方法复用。
     *
     * @param bytes 数据库返回的字节数组(可能为 null)
     * @return 解码后的字符串;若输入为 null,则返回 null
     * @throws SQLException 如果 GBK 解码失败(如字节序列不符合 GBK 规范)
     */
    private String convertFromBytes(byte[] bytes) throws SQLException {
        if (bytes == null) {
            return null;
        }
        try {
            // 使用 GBK 字符集将字节数组转换为字符串
            return new String(bytes, GBK);
        } catch (UnsupportedEncodingException e) {
            log.error("查询时转码异常:",e);
            // 理论上 GBK 总是可用,但此处仍做异常处理并包装为 SQLException
            throw new SQLException("GBK decoding failed", e);
        }
    }

    public static void main(String[] args) throws Exception {
        String shrmc = "营销总公司";
        System.out.println(chineseEncode(shrmc));
    }
}
View Code

4.数据库连接参数调整(这里使用的是Navicat 15)

image

主要设置: 客户端字符集,编码

image

 这样设置之后查询出来的中文就不是乱码了

 

 

 

 
posted @ 2026-08-07 10:23  泡沫幻影  阅读(3)  评论(0)    收藏  举报