在很久很久之前就解决过乱码问题,方法都是从网络上搜索来的。一直以来都是一知半解的。今天又费了将近两个小时来弄明白,至此刻还是不甚理解。
装Mysql时,设置的编码格式是utf8,即在my.ini里的设置显示为default-character-set=utf8 (共有2条语句,一条是客户端,一条是服务器端,貌似是这样子的说法)
在使用hibernate插件连接时,只要连接时使用如下语句就OK了。
jdbc:mysql://localhost:3306/javahomework?useUnicode=true&characterEncoding=UTF-8
而在java代码中,使用该方法插入时,无论数据库本身是utf8还是gbk,插入都是乱码。不得已修改了my.ini的default-character-set=utf8 为default-character-set=gbk .就行了。
在网上找到了如下两篇比较通俗易懂易操作的博文。如下所示:
- MySQL默认编码是latin1
- mysql> show variables like 'character%';
- +--------------------------+--------------------------+
- | Variable_name | Value |
- +--------------------------+--------------------------+
- | character_set_client | latin1 |
- | character_set_connection | latin1 |
- | character_set_database | latin1 |
- | character_set_filesystem | binary |
- | character_set_results | latin1 |
- | character_set_server | latin1 |
- | character_set_system | utf8 |
- | character_sets_dir | D:/MySQL/share/charsets/ |
- +--------------------------+--------------------------+
- 创建数据表并插入数据
- mysql> use test;
- mysql> create table messages (
- -> id int(4) unsigned auto_increment primary key,
- -> message varchar(50) not null
- -> ) engine=myisam default charset=utf8;
- mysql> insert into messages (message) values ("测试MySQL中文显示"); mysql> select * from messages;
- +----+-------------------+
- | id | message |
- +----+-------------------+
- | 1 | 测试MySQL中文显示 |
- +----+-------------------+
- 编写程序(Java)
- Java代码
- 1.import java.sql.Connection;
- 2.import java.sql.DriverManager;
- 3.import java.sql.ResultSet;
- 4.import java.sql.Statement;
- 5.public class JDBCTest {
- 6. public static void main(String[] args) {
- 7.String driver = "com.mysql.jdbc.Driver";
- 8.String url = "jdbc:mysql://localhost:3306/test";
- 9.String user = "root";
- 10.String password = "root";
- 11.try {
- 12. Class.forName(driver);
- 13. Connection conn = DriverManager.getConnection (url,user,password);
- 14. Statement stmt = conn.createStatement();
- 15. stmt.executeUpdate("insert into messages (message) values ('测试MySQL编码')");
- 16.ResultSet rs = stmt.executeQuery("select * from messages");
- 17.while (rs.next()) {
- 18. int id = rs.getInt("id");
- 19. String message = rs.getString("message");
- 20. System.out.println(id + " " + message);
- 21.}
- 22.rs.close();
- 23.stmt.close();
- 24.conn.close();
- 25.} catch (Exception e) {
- 26. e.printStackTrace();
- 27. }
- 28. }
- 29.}
- 30.程序输出 1 ????MySQL???????? 2 ??MySQL??
- import java.sql.Connection;
- import java.sql.DriverManager;
- import java.sql.ResultSet;
- import java.sql.Statement;
- public class JDBCTest {
- public static void main(String[] args) {
- String driver = "com.mysql.jdbc.Driver";
- String url = "jdbc:mysql://localhost:3306/test";
- String user = "root";
- String password = "root";
- try {
- Class.forName(driver);
- Connection conn = DriverManager.getConnection (url,user,password);
- Statement stmt = conn.createStatement();
- stmt.executeUpdate("insert into messages (message) values ('测试MySQL编码')");
- ResultSet rs = stmt.executeQuery("select * from messages");
- while (rs.next()) {
- int id = rs.getInt("id");
- String message = rs.getString("message");
- System.out.println(id + " " + message);
- }
- rs.close();
- stmt.close();
- conn.close();
- } catch (Exception e) {
- e.printStackTrace();
- }
- }
- }
- 程序输出 1 ????MySQL???????? 2 ??MySQL??
- 我们看到,尽管使用数据库时我们能够正常的添加和显示中文,但是在使用程序连接数据库时并不能够正常显示中文,为此我们需要修改MySQL的默认编码,编辑my.ini(MySQL配置文件)文件对编码进行修改
- 设置MySQL的默认字符集为utf8,找到客户端配置[client]在下面添加。
- default-character-set=utf8
- 找到服务器配置[mysqld]在下面添加
- default-character-set=utf8
- 设定MySQL数据库以utf8编码运行,连接MySQL数据库时使用utf8编码
- 停止和重新启动MySQL
- net stop mysql
- net start mysql
- 重新连接数据库,查看编码,数据表内容
- mysql> show variables like 'character%';
- +--------------------------+--------------------------+
- | Variable_name | Value |
- +--------------------------+--------------------------+
- | character_set_client | utf8 |
- | character_set_connection | utf8 |
- | character_set_database | utf8 |
- | character_set_filesystem | binary |
- | character_set_results | utf8 |
- | character_set_server | utf8 |
- | character_set_system | utf8 |
- | character_sets_dir | D:/MySQL/share/charsets/ |
- +--------------------------+--------------------------+
- mysql> use test; mysql> select * from messages;
- +----+-------------------------------+
- | id | message |
- +----+-------------------------------+
- | 1 | 虏芒脢脭MySQL脰脨脦脛脧脭脢戮 |
- | 2 | ??MySQL?? |
- +----+-------------------------------+
- 这里显示依然是乱码主要是因为之前使用的编码不同造成的,
- 重新运行之前写的程序:
- java JDBCTest 1 ????MySQL???????? 2 ??MySQL?? 3 测试MySQL编码
- 从第三条记录我们可以看到现在程序连接数据库时可以正常的添加和显示中文了
- mysql> select * from messages;
- +----+-------------------------------+
- | id | message |
- +----+-------------------------------+
- | 1 | 虏芒脢脭MySQL脰脨脦脛脧脭脢戮 |
- | 2 | ??MySQL?? |
- | 3 | 娴嬭瘯MySQL缂栫爜 |
- +----+-------------------------------+
- 看回数据库的显示,我们会很奇怪的发现为什么显示的都是乱码,这主要是和windows下命令行的编码有关,在命令行上查看属性->选项的当前代码页:936 (ANSI/OEM - 简体中文 GBK)(本人机子上是这样显示的)
- 也就是说命令行上使用的是GBK编码,而我们是在程序连接时使用utf8进行添加的,所以会出现有乱码,现在我们将客户端的编码改成gb2312或gbk试一下
- mysql> show variables like 'character%';
- +--------------------------+--------------------------+
- | Variable_name | Value |
- +--------------------------+--------------------------+
- | character_set_client | gb2312 |
- | character_set_connection | gb2312 |
- | character_set_database | utf8 |
- | character_set_filesystem | binary |
- | character_set_results | gb2312 |
- | character_set_server | utf8 |
- | character_set_system | utf8 |
- | character_sets_dir | D:/MySQL/share/charsets/ |
- +--------------------------+--------------------------+
- mysql> use test; mysql> select * from messages;
- +----+-------------------+
- | id | message |
- +----+-------------------+
- | 1 | ????MySQL???????? |
- | 2 | ??MySQL?? |
- | 3 | 测试MySQL编码 |
- +----+-------------------+
- 现在可以看到中文正常显示了(主要是因为utf8也支持中文),所以当我们使用命令行工具连接数据库的时候最好将客户端的编码改一下,如果使用GUI的话就不必了,同时修改客户端的编码之后程序依然能够正常显示(以上两点已经测试)
- 所以如果在程序中要显示中文的话我们可以选用utf8,gb2312,gbk这三种编码,但是如果想在命令行添加中文数据或者查看的话就需要将客户端的编码设置为gb2312或gbk了,还是那句,CMD的编码有关
- 对初学者来说,java与MySQL的连接以及MySQL的中文乱码问题是两个比较头疼的问题。我刚做了一个小项目,对这两个问题也是绞尽脑汁,也是初学者,花了一番功夫去查网页,找答案。作为一个初学者,我也完全以初学者的立场叙述一下我遇到的问题以及其解决的方法。也望能给刚陷入次困境的朋友有些许帮助!
- 我用的版本:
- JDK:j2sdk1.5.0
- MySQL:mysql-5.0.41-win32_178
- JDBC驱动:mysql-connector-java-3.2.0-alpha-bin.jar
- 一、java与数据库的连接
- java与数据库的连接书上写有四种方法,我的理解其实从其实质上说就两种,一种建立JDBC-ODBC桥,通过ODBC数据源与数据库相连。另一种是纯java式的连接,通过java类库API驱动连接。以MySQL为例,这两种方法分别需要MySQL-ODBC驱动和MySQL-JDBC-ODBC驱动。我用的是第二种方法,当然也建议使用纯java式的连接,需要MySQL-JDBC-ODBC驱动,可以从网上下载。
- 首先需要把驱动放在jdk的安装目录的lib目录中,并在环境变量classpath中加上该jar包,其设置和jdk的classpath中dt.jar和tools.jar一样。
- 连接过程分三步:加载驱动程序;使用java.sql包中的Connection建立连接;由Connection对象产生Statement对象,然后Statement对象就可以调用其方法传递SQL语句了。
- 下面以一个具体的实例来测试我们的连接:
- import java.sql.*;
- public class ConnectToMySQLTest
- {
- public static void main(String[] args)
- {
- try
- {
- //加载驱动程序
- Class.forName("com.mysql.jdbc.Driver");
- //创建指定数据库的URL
- String url="jdbc:mysql://localhost:3306/student"; //student是创建的数据库的名字
- String userName="root"; //root是MySQL默认的用户名
- String password="123"; //123是你设置的MySQL密码
- //创建连接
- Connection conn=DriverManager.getConnection(url,userName,password);
- //创建Statement对象
- Statement stmt=conn.createStatement();
- //Statement对象向数据库提交SQL语句
- stmt.execute("drop table if exists stu"); //若表stu存在则删除
- stmt.execute("create table stu(id int not null primary key,name varchar(20) not null,sex varchar(4))"); //创建表stu
- //插入记录
- stmt.execute("insert into stu values(1,'aaa','boy')");
- stmt.execute("insert into stu values(2,'bbb','girl')");
- stmt.execute("insert into stu values(3,'ccc','girl')");
- //执行查询数据库操作,并返回查询的结果集
- ResultSet rs=stmt.executeQuery("select * from stu");
- //将结果集表指针定位到第一条记录前
- rs.beforeFirst();
- //打印查询结果
- System.out.println("stu表的数据如下:");
- System.out.println("---------------------");
- System.out.println("学号/t姓名/t性别");
- System.out.println("---------------------");
- int num;
- String name;
- String sex;
- while (rs.next())
- {
- num=rs.getInt("id");
- name=rs.getString("name");
- sex=rs.getString("sex");
- System.out.println(num+"/t"+name+"/t"+sex);
- }
- stmt.close();
- conn.close();
- }
- catch (Exception e)
- {
- e.printStackTrace();
- }
- }
- }
- 在测试之前,你需要启动MySQL,在mysql命令窗口中输入:create database student; 回车建立student数据库,然后在命令提示符中编译运行ConnectToMySQLTest,即可出现如下结果:
- 二、MySQL中文乱码问题
- 首先我们先来做个测试:
- 上面的代码运行成功后,打开mysql命令窗口,在其中输入:use student; (回车选择数据库)
- select * from stu; (回车出现如下查询结果)
- 然后把上面代码stmt.execute("insert into stu values(1,'aaa','boy')");中的'aaa'改为'张三',然后保存重新编译运行,运行的结果为:
- 我们再打开mysql命令窗口,因为刚才我们已经选择了student数据库,我们可以直接输入:select * from stu; (回车查询) 结果如下:
- 可以发现改成张三以后,运行结果正常显示,但mysql中却显示的是两个问号。
- MySQL默认的字符编码是latin1,与java对应的就是ISO-8859-1。所以要正确的显示我们的中文字符,只需要将MySQL的字符编码方式有latin1改成中文的就行了,改成“gbk”或"gb2312",修改的方法有两种:
- 一种是重新配置MySQL,在它的配置向导中有一项是让你选择字符的编码,你可以选择自定义选项,然后将其自定义为“gbk”或“gb2312”;
- 另一种是直接修改MySQL安装目录中的“my.ini”文件,在MySQL的安装目录下找到该文件,用记事本打开,在其中找到以下两句:
- [my sql]
- default-character-set=latin1
- [my sqld]
- ……
- ……
- default-character-set=latin1
- 分别将其中的latin1改成“gbk”即可,注意要用小写,听说大写不识别。
- 网上还有几种其他的方法,在这里也说一下,有一种是在连接数据的连接串中指定字符集和Unicode编码,他把数据库的URL写成:
- String url="jdbc:mysql://localhost:3306/student?user=root&password=123&useUnicode=true&characterEncoding=gb2312";
- 这样写的目的是告诉驱动在与数据库进行转码的时候按照这种方式来转,从而避免乱码,这种方法只能解决从java从MySQL中取出数据输出时的乱码问题,但若从java中向MySQL中插入中文数据时,在MySQL中仍然显示的是乱码,因为你并没有修改MySQL的字符编码方式,它还是默认的latin1,所以中文仍然不能正常显示,换句话也就是说,若MySQL的编码方式是latin1,你java向其中插入中文时,在MySQL中永远是乱码,它只能正确显示在MySQL中直接向其插入的中文,从外界向其插入中文它是不能正常显示的。
- 还有一种方法是,再使java从MySQL中取出数据时让其由"latin1"转化为"gbk",从java向MySQL中插入数据时让其由"gbk"转化为"latin1",以取出数据为例,经过这样的转化:
- String name=new String(rst.getString("name").getBytes("ISO-8859-1"),"GBK");
- 这里注意:gbk在java中是大写,小写会出错。latin1在java中对应的是ISO-8859-1.
- 也可以写两个转化函数,在转化时通过调用函数去转化,这两个函数如下:
- import java.io.UnsupportedEncodingException;
- //解决中文问题
- public class EncodingUtil {
- //从数据库取出用
- public static String latin1ToGBK(String str)
- {
- try {
- String temp_p = str;
- byte[] temp_t = temp_p.getBytes("ISO-8859-1");
- String temp = new String(temp_t,"GBK");
- return temp;
- }catch (UnsupportedEncodingException ex) {
- System.out.println(ex);
- return "";
- }
- }
- //存入中文数据时用
- public static String GBKToLatin1(String str)
- {
- if(str==null)
- {
- str="";
- }
- else{
- try{
- str=new String(str.getBytes("GBK"),"ISO-8859-1");
- }
- catch(Exception ex){
- ex.printStackTrace();
- }
- }
- return str;
- }
- }
- 但这种用于较少的数据库操作的话还行,若你要频繁的从数据库中存取数据,那么每一句存取的语句你都去调用方法去转化,那显然是行不通的。
- 写到这里,我再多说一点,我自己的理解对于后两种方法,应该是在早期驱动程序不完善的时候出现问题的解决方法,可能驱动程序中对两种编码的转化没有能很好的实现,从而导致的存取乱码问题,我在网上就见过有人通过修改mysql-jdbc驱动去解决问题,因为mysql-jdbc驱动是开放源码的,他通过修改程序,重新编译生成class文件,然后运行不出现任何问题,很牛的人。
- 我自己的理解认为:现在的驱动已经完善了,所以在存取数据库时,不会出现乱码问题,乱码问题只是数据库使用的编码方式若不是中文的,那么在向其插入中文数据时,它不能正确显示出来,我们只需修改数据库的编码方式即可OK了。
- 还有注意:不同版本的MySQL会有不同的结果,这个很奇怪,网上有人说MySQL数据库的东西都是二进制存放的,支持任何数据,当然包括中文,你在MySQL命令行下输入:
- insert into stu values(4,'李四','boy');
- select * from stu;
- 会正确显示李四,而如果你在java中向其插入该条记录,再在MySQL中查看,就成??了,他的意思是证明了乱码出现的原因是在java与MySQL的连接部分,也即驱动不能正确转化。我在mysql-5.0.51a-win32中这样测试过,确实是这样的,但你在我们现在用的mysql-5.0.41-win32_178中测试,若MySQL编码为latin1时,在MySQL命令中插入中文记录时,会出现错误:ERROR:1366(HY000)Incorrect string value: .....
- 也即在mysql-5.0.41-win32_178中,若编码为latin1时,它不让我们直接插入中文数据,但不知为何在mysql-5.0.51a-win32却可以,这是个疑问,有知人士可以给出解答,在这先谢了。
高亮显示方便学习。