我是靠谱客的博主 暴躁板栗,最近开发中收集的这篇文章主要介绍解决Mybatis3.3中NVARCHAR2生僻字乱码1. 解决Mybatis3.3中NVARCHAR2生僻字乱码,觉得挺不错的,现在分享给大家,希望可以做个参考。

概述

文章目录

  • 1. 解决Mybatis3.3中NVARCHAR2生僻字乱码
    • 1.1. 注意
    • 1.2. 解决方法
      • 1.2.1. 第一步、数据库的varchar2字段修改为nvarchar2
      • 1.2.2. 第二步、mybatis中原来的`jdbcType=VARCHAR`修改为`jdbcType=NVARCHAR`
      • 1.2.3. 第三步、重写NVARCHAR的类型处理
      • 1.2.4. 注意,还需要在mybatis-config.xml中配置一下
    • 1.3. 总结

1. 解决Mybatis3.3中NVARCHAR2生僻字乱码

在数据库中原来的字符串类型都是用varchar2类型存储,现在发现生僻字乱码,遂改为NVARCHAR2,但是依然生僻字乱码。

1.1. 注意

  1. 使用的mybatis版本是3.3,不知道再其它版本中是否有同样问题
  2. 这里的乱码和前后端文件等编码无关,即所有中文存入varchar2,只有生僻字乱码,其它正常

1.2. 解决方法

1.2.1. 第一步、数据库的varchar2字段修改为nvarchar2

  因为varchar2和数据库的字符集有关系,而数据库在ZHS16GBK(应该是等同于GBK吧?!)编码下,不包含生僻字;修改为AL32UTF8后mybatis居然把所有从数据库查出的中文显示为乱码了。。。所以只能使用nvarchar2。由此可以总结出:varchar2与数据库字符集有关,而nvarchar2则与数据库字符集无关(可以在varchar2和nvarchar2字段中手动输入生僻字即可看到证据)

1.2.2. 第二步、mybatis中原来的jdbcType=VARCHAR修改为jdbcType=NVARCHAR

  如果不修改的话,mybatis的类型处理器,默认会使用StringTypeHandler来处理,StringTypeHandler源码如下,可以看出使用的依然是setString

//
// Source code recreated from a .class file by IntelliJ IDEA
// (powered by Fernflower decompiler)
//

package org.apache.ibatis.type;

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

public class StringTypeHandler extends BaseTypeHandler<String> {
    public StringTypeHandler() {
    }

    public void setNonNullParameter(PreparedStatement ps, int i, String parameter, JdbcType jdbcType) throws SQLException {
        ps.setString(i, parameter);
    }

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

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

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

再来看NStringTypeHandler

//
// Source code recreated from a .class file by IntelliJ IDEA
// (powered by Fernflower decompiler)
//

package org.apache.ibatis.type;

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

public class NStringTypeHandler extends BaseTypeHandler<String> {
    public NStringTypeHandler() {
    }

    public void setNonNullParameter(PreparedStatement ps, int i, String parameter, JdbcType jdbcType) throws SQLException {
        ps.setString(i, parameter);
    }

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

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

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

看上去和StringTypeHandler一样呀,调试了几个小时才调好,方法是重写NStringTypeHandler,如下第三步

1.2.3. 第三步、重写NVARCHAR的类型处理

如下,暂时只处理了set方法(即改为setNString),因为get出来的结果生僻字没问题,所以没有修改。

package com.ufgov.util.mybatis;

import org.apache.ibatis.type.*;

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

/**
 * NVARCHAR汉字生僻字乱码问题。
 * 主要是NStringTypeHandler中,没有setNString()
 */
@MappedJdbcTypes(JdbcType.NVARCHAR)
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);
  }
}

1.2.4. 注意,还需要在mybatis-config.xml中配置一下


    <typeHandlers>
        <typeHandler handler="com.ufgov.util.mybatis.NVarcharTypeHandler"/>
    </typeHandlers>

1.3. 总结

  1. 数据库字符集,utf8比gbk范围更大,gbk无法现在生僻字。
  2. varchar2与数据库字符集有关,nvarchar与数据库字符集无关
  3. 也许mybatis对NVARCHAR的处理有bug,在NStringTypeHandler中居然没有setNString
  4. 由此可见,PreparedStatementsetStringsetNString实现也是不同的,可以看看源码。

最后

以上就是暴躁板栗为你收集整理的解决Mybatis3.3中NVARCHAR2生僻字乱码1. 解决Mybatis3.3中NVARCHAR2生僻字乱码的全部内容,希望文章能够帮你解决解决Mybatis3.3中NVARCHAR2生僻字乱码1. 解决Mybatis3.3中NVARCHAR2生僻字乱码所遇到的程序开发问题。

如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。

本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
点赞(47)

评论列表共有 0 条评论

立即
投稿
返回
顶部