前段时间学习 JDBC, 要连接 mysql 获取数据. 按照老师的样例数据, 要存一些名字之类的信息, 用的都是英文名, 我当时就不太想用英文, 就把我室友的名字存了进去, 嘿嘿, 结果, 出问题了.
连接数据库语句:
static final String DB_URL = "jdbc:mysql://localhost/filemanagement";
查询语句:
private static final String theUserQuery = "SELECT name, password, role FROM userinfo WHERE name = ?";
我是用我的名字做的查询, NullPointerException, 很明显, 没有用我的名字查到对应的数据, 而数据库中是存在的. 这是为什么呢?
百度到的答案是中文乱码导致的查询不到东西, 解决方案是, 修改连接数据库语句为:
static final String DB_URL = "jdbc:mysql://localhost/filemanagement?useUnicode=true&characterEncoding=GBK";
重试!
可以了! 但这是为什么呢? 那两个参数是什么? 为什么加上之后就解决问题了?
这两个参数解释如下:
两个参数的缺省值都是 false. 也就是说我们在连接 mysql 的时候指定了连接使用的字符集后, 一切就正常了. 但我还是不太了解其中的机制, 所以继续查.
原来 Mysql 连接进行查询等操作时存在一个字符集转换过程:
1.MySQL Server 收到请求时将请求数据从 character_set_client 转换为 character_set_connection;
2. 进行内部操作前将请求数据从 character_set_connection 转换为内部操作字符集, 其确定方法如下:
使用每个数据字段的 CHARACTER SET 设定值;
若上述值不存在, 则使用对应数据表的 DEFAULT CHARACTER SET 设定值(MySQL 扩展, 非 SQL 标准);
若上述值不存在, 则使用对应数据库的 DEFAULT CHARACTER SET 设定值;
若上述值不存在, 则使用 character_set_server 设定值.
3. 将操作结果从内部操作字符集转换为 character_set_results.
这些 character set 代表什么呢?
character_set_server: 默认的内部操作字符集
character_set_client: 客户端来源数据使用的字符集
character_set_connection: 连接层字符集
character_set_results: 查询结果字符集
character_set_database: 当前选中数据库的默认字符集
character_set_system: 系统元数据 (字段名等) 字符集
还查到了一些常见问题, 虽然和我的问题不太一样, 但很有参考意义.
向默认字符集为 utf8 的数据表插入 utf8 编码的数据前没有设置连接字符集, 查询时设置连接字符集为 utf8
- 插入时根据 MySQL 服务器的默认设置, character_set_client,character_set_connection 和 character_set_results 均为 latin1;
- 插入操作的数据将经过 latin1=>latin1=>utf8 的字符集转换过程, 这一过程中每个插入的汉字都会从原始的 3 个字节变成 6 个字节保存;
- 查询时的结果将经过 utf8=>utf8 的字符集转换过程, 将保存的 6 个字节原封不动返回, 产生乱码......
向默认字符集为 latin1 的数据表插入 utf8 编码的数据前设置了连接字符集为 utf8
- 插入时根据连接字符集设置, character_set_client,character_set_connection 和 character_set_results 均为 utf8;
- 插入数据将经过 utf8=>utf8=>latin1 的字符集转换, 若原始数据中含有 \ u0000~\u00ff 范围以外的 Unicode 字 符, 会因为无法在 latin1 字符集中表示而被转换为 "?"(0x3F)符号, 以后查询时不管连接字符集设置如何都无法恢复其内容了.
(此部分摘自鸟哥的 blog, 稍后附上链接)
我数据库的表都是设置的 utf8 编码, 但我第一次连接的时候没有设置连接字符集, 所以默认为 latin1, 经过了从 utf8=>latin1 的转换, 所以产生乱码. 我第二次用的 GBK 编码, 也没用 utf8 编码, 为什么也可以了呢? 其实是一个道理, 中文不在 latin1 的编码中可是在 GBK 和 utf8 中, 所以不会出问题.
到此为止所有的疑问都解开了, 大家是否懂了呢?
附上参考博客链接:
- http://www.laruence.com/2008/01/05/12.html
- http://m.blog.csdn.net/zhliro/article/details/45464375
来源: https://juejin.im/entry/5ac746406fb9a028d56758c8