在Oracle到GreatSQL迁移中排序规则改变引发的乱码问题分析及解决

一、引言

某老系统数据库从 Oracle 迁移至 GreatSQL 过程中,首批迁移(存储过程、表结构、基础数据)顺利完成。然而,第二批数据迁移时出现主键冲突问题:原Oracle数据库中存在主键字段A与a(忽略大小写后视为相同值),但 GreatSQL 默认排序规则 utf8mb4_0900_ai_ci 不区分大小写,导致主键冲突。

为解决此问题,将排序规则调整为 utf8mb4_0900_bin 以区分大小写。但调整后,Java程序读取中文字段时出现乱码(如“好”显示为“好”),直接影响业务功能。本文从环境兼容性、驱动版本、字符编解码机制等角度深入分析问题根源,并提供三种解决方案。

二、环境说明与问题背景

关键组件版本:

组件版本号备注
数据库GreatSQL 8.0.32-26默认字符集utf8mb4
jdk1.7.0_80旧版本,升级成本高
驱动版本mysql-connector-java 5.1.46官方已停止维护
字符集utf8mb4未变动
排序规则utf8mb4_0900_ai_ci->utf8mb4_0900_bin变更后引发乱码

核心矛盾点

  • 业务需求:需使用 utf8mb4_0900_bin 排序规则解决主键冲突。
  • 环境限制:旧版 JDK 1.7 与低版本驱动(5.1.46)存在兼容性问题,无法正确解析新排序规则。

三、复现过程

1. 创建测试表并插入数据

greatsql> CREATE TABLE test.t1(id int PRIMARY KEY, cname varchar(10)) DEFAULT charset=utf8mb4 collate=utf8mb4_0900_ai_ci;
Query OK, 0 rows affected (0.02 sec)
greatsql> INSERT INTO test.t1 VALUES(1, '好');
Query OK, 1 row affected (0.00 sec)

确认 Java 版本

$ javac -version
javac 1.7.0_80
$ java -version
java version "1.7.0_80"
Java(TM) SE Runtime Environment (build 1.7.0_80-b15)
Java HotSpot(TM) 64-Bit Server VM (build 24.80-b11, mixed mode)

编写 SimpleDBQuery.java,其内容如下:

import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.Statement;
public class SimpleDBQuery {
 public static void main(String[] args) {
 String url = "jdbc:mysql://172.17.134.66:3301/test?characterEncoding=UTF-8&useSSL=false";
 String username = "bing";
 String password = "abc123";
 Connection conn = null;
 Statement stmt = null;
 ResultSet rs = null;
 try {
 Class.forName("com.mysql.jdbc.Driver");
 conn = DriverManager.getConnection(url, username, password);
 String sql = "SELECT cname FROM t1 LIMIT 1";
 stmt = conn.createStatement();
 rs = stmt.executeQuery(sql);
 if (rs.next()) {
 String value = rs.getString("cname");
 System.out.println(" 查询结果: " + value);
 }
 } catch (Exception e) {
 e.printStackTrace();
 } finally {
 try {
 if (rs!= null) rs.close();
 if (stmt!= null) stmt.close();
 if (conn!= null) conn.close();
 } catch (Exception e) {
 e.printStackTrace();
 }
 }
 }
}

2.Java程序读取数据(正常)

$ javac -cp .:mysql-connector-java-5.1.46.jar SimpleDBQuery.java
$ java -cp .:mysql-connector-java-5.1.46.jar SimpleDBQuery
 查询结果: 好

3.修改排序规则后复现乱码

greatsql> ALTER TABLE test.t1 CONVERT TO charset utf8mb4 COLLATE utf8mb4_0900_bin;
Query OK, 0 rows affected (0.04 sec)
Records: 0 Duplicates: 0 Warnings: 0

再次通过 Java 程序访问数据库中的汉字,则出现乱码: