记一次数据库为latin1编码查询中文乱码问题处理

以下是个人项目中采用的方法,应该还有其他更有优雅完善的方式。这里先记录下,后面碰到就可以很快填坑了
一、问题描述:
因项目需求,需要整合多个项目一起,其中一个项目因在创建数据库的时候没有设置编码格式,为默认的latin1编码。这就导致查询遇到中文的时候会出现乱码,需要进行转码操作。

二、问题处理过程(本项目为springboot+mybatis):
1、经过多次验证,发现原来数据库的插入数据格式为gbk,然而数据库编码为latin1格式的。网上给出的方案大部分是备份库,然后重新调整数据库编码格式什么的。实际情况,首先风险不说,大部分情况是不允许这么操作,如涉及到别的项目对这个已经进行过处理,如果改变了编码,也许自己项目没有问题,但也会导致别的用这个库的项目受到影响。
2、设置项
2.1、多数据源配置(注意加粗的地方,然后url中characterEncoding的编码格式根据实际需要设置,如果原来库中是gbk就设置为gbk):

spring:
  datasource:
    db1:
      #jdbc-url: jdbc:mysql://host:3306/db1?useUnicode=true&characterEncoding=UTF-8&serverTimezone=Asia/Shanghai
      url: jdbc:mysql://host:3306/db1?useUnicode=true&characterEncoding=gbk&serverTimezone=Asia/Shanghai
      username: root
      password: ***
        # 驱动
      type: com.alibaba.druid.pool.DruidDataSource
      driver-class-name: com.mysql.jdbc.Driver
      mybatis:
        type-aliases-package: com.saas.mall.jz.rmi.dao.admin
      #设置连接指定编码配置项
      connectionInitSqls: set names latin1
    db2:
      #jdbc-url: jdbc:mysql://host:3306/db2?useUnicode=true&characterEncoding=gbk&serverTimezone=Asia/Shanghai
      url: jdbc:mysql://host:3306/db2?useUnicode=true&characterEncoding=gbk&serverTimezone=Asia/Shanghai
      username: root
      password: ***
        # 驱动
      type: com.alibaba.druid.pool.DruidDataSource
      driver-class-name: com.mysql.jdbc.Driver
      mybatis:
        type-aliases-package: com.saas.mall.jz.rmi.dao.website
      connectionInitSqls: set names latin1
    db3:
      url: jdbc:mysql://host:3306/db3?useUnicode=true&characterEncoding=gbk&serverTimezone=Asia/Shanghai
      username: root
      password: ****
      # 驱动
      type: com.alibaba.druid.pool.DruidDataSource
      driver-class-name: com.mysql.jdbc.Driver
      mybatis:
        type-aliases-package: com.saas.mall.jz.rmi.dao.evyun
      connectionInitSqls: set names latin1

2.2、 java配置项(多数据源需要配置,单数据源只需要配置文件中配置相应项就可以,下面为其中一个数据源的配置,注意DataSource需要是DruidDataSourceBuilder的,只有druid的数据源connectionInitSqls的配置才有用):

 package com.saas.mall.jz.rmi.config;

import com.alibaba.druid.spring.boot.autoconfigure.DruidDataSourceBuilder;
import org.apache.ibatis.session.SqlSessionFactory;
import org.mybatis.spring.SqlSessionFactoryBean;
import org.mybatis.spring.SqlSessionTemplate;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.io.support.PathMatchingResourcePatternResolver;

import javax.sql.DataSource;

/**
 * @Description: admin数据库数据源配置
 * @Creater: sunxiang
 * @CreateTime: 2020年12月21日 下午 14:10
 **/
@Configuration
@MapperScan(basePackages = "com.saas.mall.jz.rmi.dao.admin.mapper", sqlSessionFactoryRef = "adminSqlSessionFactory")
public class DataSourceAdminConfig {

    @Bean("adminDataSource")
    @ConfigurationProperties(prefix = "spring.datasource.db1")
    public DataSource getDb1DataSource(){
    //注意是DruidDataSourceBuilder 而不是DataSourceBuilder,后者的话设置无效
        return DruidDataSourceBuilder.create().build();
    }

    @Bean("adminSqlSessionFactory")
    public SqlSessionFactory db1SqlSessionFactory(@Qualifier("adminDataSource") DataSource dataSource) throws Exception {
        SqlSessionFactoryBean bean = new SqlSessionFactoryBean();
        bean.setDataSource(dataSource);

        bean.setMapperLocations(new PathMatchingResourcePatternResolver().getResources("classpath*:sqlMapper/admin/*.xml"));
        return bean.getObject();
    }

    @Bean("adminSqlSessionTemplate")
    public SqlSessionTemplate db1SqlSessionTemplate(@Qualifier("adminSqlSessionFactory") SqlSessionFactory sqlSessionFactory){
        return new SqlSessionTemplate(sqlSessionFactory);
    }
}

通过上面的配置,再插入和修改数据的时候在执行具体sql语句之前会将连接编码设置为 latin1格式的,保证与数据库编码一致。重点是配置文件中:connectionInitSqls: set names latin1 这个配置。具体作用自行百度下就知道了。这样就解决了插入数据的问题。
2.3、获取数据:
如果不做任何处理在获取数据的时候也会有乱码,因为查出来的为latin1编码格式。指导思路是对该编码转换,我的想法是:String s = new String(params.getBytes("ISO-8859-1"), "gbk");
上述语句中 params为乱码的字段名。
其中利用了mybatis的拦截器对所有的进行拦截处理:

package com.saas.mall.jz.rmi.filter;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.saas.mall.jz.rmi.util.BeanCopyUtil;
import org.apache.ibatis.executor.Executor;
import org.apache.ibatis.mapping.MappedStatement;
import org.apache.ibatis.plugin.*;
import org.apache.ibatis.session.ResultHandler;
import org.apache.ibatis.session.RowBounds;
import org.springframework.stereotype.Component;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Properties;

@Component
//拦截Executor类的query方法
@Intercepts({@Signature(type = Executor.class, method = "query", args = {MappedStatement.class, Object.class, RowBounds.class, ResultHandler.class})})
public class MybatisInterceptor implements Interceptor {

    @SuppressWarnings({"rawtypes", "unchecked"})
    public Object intercept(Invocation invocation) throws Throwable {
        Object result = invocation.proceed(); //执行请求方法,并将所得结果保存到result中
        if (result instanceof ArrayList) {
            List list = new ArrayList();
            ArrayList resultList = (ArrayList) result;
            for (int i = 0; i < resultList.size(); i++) {
                Object object = resultList.get(i);
                if (object instanceof Integer || object instanceof Long) {
                    list.add(object);
                } else {
                    Class<?> aClass = object.getClass();
                    //对object进行转码,然后重新赋值返回,如果其他类型需要自行根据实际情况进行处理,ISO-8859-1对应的即为latin1编码
                    String s = new String(JSONObject.toJSONString(object).getBytes("ISO-8859-1"), "gbk");
                    Object object1 = JSONObject.toJavaObject(JSON.parseObject(s), aClass);
                    list.add(object1);
                }
            }
            return list;
        }
        return result;
    }

    public Object plugin(Object target) {
        return Plugin.wrap(target, this);
    }

    public void setProperties(Properties arg0) {
    }
}

注入上面的拦截器使生效:

import com.saas.mall.jz.rmi.filter.MybatisInterceptor;
import org.apache.ibatis.session.SqlSessionFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.AutoConfigureAfter;
import org.springframework.context.annotation.Configuration;

import javax.annotation.PostConstruct;
import java.util.List;
import java.util.Properties;

@Configuration
public class MyBatisConfig {

    @Autowired
    private List<SqlSessionFactory> sqlSessionFactoryList;

    @PostConstruct
    public void addMySqlInterceptor() {
        //自己定义的插件拦截器类,注入到sqlSessionFactory配置中
        MybatisInterceptor interceptor = new MybatisInterceptor();
        for (SqlSessionFactory sqlSessionFactory : sqlSessionFactoryList) {
            sqlSessionFactory.getConfiguration().addInterceptor(interceptor);
        }
    }

}

上面的操作就完美实现插入和查询的中文乱码问题。

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值