写点什么

【YashanDB 知识库】YashanDB 的 JDBC/OCI 驱动如何设置字符编码

作者:YashanDB
  • 2024-07-25
    广东
  • 本文字数:1768 字

    阅读完需:约 6 分钟

问题现象

Oracle、Mysql 数据库链接串,JDBC 驱动连接串可以指定客户端的编码格式:


jdbc:mysql://hostname:port/database_name?useUnicode=true&characterEncoding=utf8mb4


jdbc:oracle:thin:@//hostname:port/service_name?NLS_LANGUAGE=AMERICAN&NLS_TERRITORY=AMERICA&NLS_CHARACTERSET=UTF8


YashanDB JDBC 连接串没有对应的参数:连接数据库 | YashanDB Doc



经常收到客户的反馈,YashanDB JDBC 没有对应的字符编码参数设置,客户端和服务端编码不一致,要怎么处理?同样的 OCI 接口是否有对应的字符编码参数可以设置?

问题的风险及影响

YashanDB 已解决,无风险。

问题影响的版本

YashanDB JDBC/OCI 驱动所有版本

问题发生原因

使用问题,详见问题分析和处理过程。

解决方法及规避方式

非问题,无须规避

问题分析和处理过程

了解字符编码

通常我们会遇到 UTF-8、GBK,为了解背后的机制,还需要了解字符集、编码的一些知识:


  • 字符集:抽象二进制和字符间的对应关系,这套对应关系不考虑具体实现,只确定映射本身。GBK 就是一套字符集。

  • 编码:计算机二进制和字符间的对应关系的实际编码实现,这套映射体现在计算机实际存储字符串的二进制序列上。UTF-8 就是一种编码的方式。

  • ASCII 码:一共规定了 128 个字符的编码,最前面的一位统一规定为 0

  • Unicode:国际标准字符集,现在的规模可以容纳 100 多万个符号。每个符号的编码都不一样。

  • UTF-8:Unicode Transformation Format,互联网上使用最广的 Unicode 的一种实现,对英文使用 8 位(即一个字节),中文使用 24 位(三个字节)来编码,另外还有 UTF-16、Oracle 常见的 AL32UTF8 等

  • GBK: 严格来说是汉字字符集定义,也可以看做字符编码方式,因为它定义汉字字符集的同时也规定了如何将这些字符编码转换为二进制字节序列。有下面多种,GB2312 使用 2 个字节来编码。



GBK、GB2312 等与 UTF8 之间通过 Unicode 编码能相互转换:


  • GBK、GB2312 --先转--> Unicode --再转--> UTF8

  • UTF8 --先转--> Unicode --再转--> GBK、GB2312


相应的资料比较多,可以参考这篇:字符编码那点事:快速理解ASCII、Unicode、GBK和UTF-8 - 知乎 (zhihu.com)

YashanDB JDBC 自动转码

JAVA 的 StringCoding 提供了字符转换工具,YashanDB JDBC 驱动利用了该工具实现了自动编解码:


首先驱动会读取 JVM 的编码设置,假如服务端字符集与 JVM 字符集不同,则:


  • 把数据从客户端传到服务端时,JDBC 自动按照服务端设置的字符集进行转换。

  • 从服务端传数据到客户端时,JDBC 按照客户端设置的字符集进行编码。


/** * Encodes this {@code String} into a sequence of bytes using the given * {@linkplain java.nio.charset.Charset charset}, storing the result into a * new byte array. * * <p> This method always replaces malformed-input and unmappable-character * sequences with this charset's default replacement byte array. The * {@link java.nio.charset.CharsetEncoder} class should be used when more * control over the encoding process is required. * * @param charset * The {@linkplain java.nio.charset.Charset} to be used to encode * the {@code String} * * @return The resultant byte array * * @since 1.6 */public byte[] getBytes(Charset charset) {    if (charset == null) throw new NullPointerException();    return StringCoding.encode(charset, value, 0, value.length);}
复制代码


所以无论在什么情况下都不会出现乱码问题,用户不需要去关心 JDBC 字符集,也不需要设置字符集。

YashanDB OCI 指定客户端编码

OCI 需要指定客户端的字符集,相关的语句:


errcode = OCIEnvNlsCreate((OCIEnv**)&envhpSessionRelease, (ub4)OCI_THREADED, (dvoid*)0,(dvoid * (*)(dvoid*, size_t))0, (dvoid * (*)(dvoid*, dvoid*, size_t))0,(void (*)(dvoid*, dvoid*))0, (size_t)0, (dvoid**)0, 852, 0);
复制代码


目前崖山只支持 852 和 871:


#define YCI_UTF8ID 871#define YCI_ZHS16GBK 852
复制代码


例如要指定编码格式为 GBK,就把 852 通过该接口传进去,崖山的 OCI 接口就可以通过 852 来识别出是要支持 ZHS16GBK,具体支持的值对应的字符集参考:oracle Nls_Charset_Id 字符集编码表_1507对应的字符集编码-CSDN博客

经验总结

1、JDBC 不需要指定编码格式,会自动编解码。

2、OCI 需要通过接口 OCIEnvNlsCreate 指定编码格式,目前只支持 2 种编码。

用户头像

YashanDB

关注

全自研国产新型大数据管理系统 2022-02-15 加入

还未添加个人简介

评论

发布
暂无评论
【YashanDB知识库】YashanDB的JDBC/OCI驱动如何设置字符编码_yashandb_YashanDB_InfoQ写作社区