JAVA 数据库连接编码问题

转载:http://hi.baidu.com/sosyq_bd/blog/item/c42d8330b8db7557ad4b5f94.html

java中String的编码格式为unicode,如果要将中文插入mysql,则表中字符列的编码属性应该设为utf-8.

create table seugs( 

  number int(11) default NULL,

  name nchar(10) default NULL,

  sex nchar(4) default NULL,

  home nchar(100) default NULL,

  college nchar(50) default NULL,

  benke nchar(50) default NULL,

  birth date default NULL,

  rxtime date default NULL

) ENGINE=InnoDB DEFAULT CHARSET=utf8。

在java连接mysql时,连接语句可设置字符集,语法如下,注意表名跟属性设置之间用问号连接

conn = DriverManager.getConnection("jdbc:mysql://localhost:3306/test?useUnicode=true&characterEncoding=utf8", "root", "syq"); 

如果使用命令行或者IDE工具直接执行SQL语句,如果查询条件里有中文,则还应该设置MYSQL的字符编码。原因如下:

 MySQL处理连接时,外部连接发送过来的SQL请求会根据以下顺序进行转换:
character_set_client             //客户连接所采用的字符集
        |
character_set_connection       //MySQL连接字符集
        |
character_set_database         //数据库所采用的字符集(表,列)
        |
character_set_results           //客户机显示所采用的字符集


一. 产生乱码的根本原因在于:
1.客户机没有正确地设置client字符集,导致原先的SQL语句被转换成connection所指字符集,而这种转换,是会丢失信息的,如果client是utf8格式,那么如果转换成gb2312格式,这其中必定会丢失信息,反之则不会丢失。一定要保证connection的字符集大于client字符集才能保证转换不丢失信息。
2. 数据库字体没有设置正确,如果数据库字体设置不正确,那么connection字符集转换成database字符集照样丢失编码,原因跟上面一样。

设置方法:

在my.ini或者my.cnf中修改这两个参数

[mysqld]
default-character-set=utf8
[mysql]
default-character-set=utf8

转载一个java编码问题的网页

Java与Unicode:

Java的class文件采用utf8的编码方式,JVM运行时采用utf16

Java的字符串是unicode编码的。

总之,Java采用了unicode字符集,使之易于国际化。

 

Java支持哪些字符集:

 

即Java能识别哪些字符集并对它进行正确地处理?

查看Charset 类,最新的JDK支持160种字符集。可以通过static方法availableCharsets拿到所有Java支持的字符集。

Java代码  

assertEquals(160, Charset.availableCharsets().size());    Set<String> charsetNames = Charset.availableCharsets().keySet();    assertTrue(charsetNames.contains("utf-8"));  assertTrue(charsetNames.contains("utf-16"));  assertTrue(charsetNames.contains("gb2312"));    assertTrue(Charset.isSupported("utf-8"));  

 

需要在哪些时候注意编码问题?

 

1. 从外部资源读取数据:

这跟外部资源采取的编码方式有关,我们需要使用外部资源采用的字符集来读取外部数据:

Java代码  

InputStream is = new FileInputStream("res/input2.data");  InputStreamReader streamReader = new InputStreamReader(is, "GB18030"); 

这里可以看到,我们采用了GB18030编码读取外部数据,通过查看streamReader的encoding可以印证:

Java代码  

assertEquals("GB18030", streamReader.getEncoding());  

正是由于上面我们为外部资源指定了正确的编码,当它转成char数组时才能正确地进行解码(GB18030 -> unicode):

 

Java代码  

char[] chars = new char[is.available()];  streamReader.read(chars, 0, is.available());   

但我们经常写的代码就像下面这样:

Java代码  

InputStream is = new FileInputStream("res/input2.data");  InputStreamReader streamReader = new InputStreamReader(is);  

这时候InputStreamReader采用什么编码方式读取外部资源呢?Unicode?不是,这时候采用的编码方式是JVM的默认字符集,这个默认字符集在虚拟机启动时决定,通常根据语言环境和底层操作系统的 charset 来确定。可以通过以下方式得到JVM的默认字符集:

Java代码  

Charset.defaultCharset();   

为什么要这样?因为我们从外部资源读取数据,而外部资源的编码方式通常跟操作系统所使用的字符集一样,所以采用这种默认方式是可以理解的。

好吧,那么我通过我的IDE Ideas创建了一个文件,并以JVM默认的编码方式从这个文件读取数据,但读出来的数据竟然是乱码。为何?呵呵,其实是因为通过Ideas创建的文件是以utf-8编码的。要得到一个JVM默认编码的文件,通过手工创建一个txt文件试试吧。

 

2. 字符串和字节数组的相互转换 

我们通常通过以下代码把字符串转换成字节数组:

Java代码  

"string".getBytes();  

但你是否注意过这个转换采用的编码呢?其实上面这句代码跟下面这句是等价的:

Java代码  

"string".getBytes(Charset.defaultCharset());  

也就是说它根据JVM的默认编码(而不是你可能以为的unicode)把字符串转换成一个字节数组。

反之,如何从字节数组创建一个字符串呢?

Java代码  

new String("string".getBytes());  

同样,这个方法使用平台的默认字符集解码字节的指定数组(这里的解码指从一种字符集到unicode)。

 

字符串编码迷思:

Java代码  

new String(input.getBytes("ISO-8859-1"), "GB18030")   

上面这段代码代表什么?有人会说: “把input字符串从ISO-8859-1编码方式转换成GB18030编码方式”。如果这种说法正确,那么又如何解释我们刚提到的java字符串都采用unicode编码呢?

这种说法不仅是欠妥的,而且是大错特错的,让我们一一来分析,其实事实是这样的:我们本应该用GB18030的编码来读取数据并解码成字符串,但结果却采用了ISO-8859-1的编码,导致生成一个错误的字符串。要恢复,就要先把字符串恢复成原始字节数组,然后通过正确的编码GB18030再次解码成字符串(即把以GB18030编码的数据转成unicode的字符串)。注意,字符串永远都是unicode编码的。

但编码转换并不是负负得正那么简单,这里我们之所以可以正确地转换回来,是因为 ISO8859-1 是单字节编码,所以每个字节被按照原样 转换为String ,也就是说,虽然这是一个错误的转换,但编码没有改变,所以我们仍然有机会把编码转换回来!

总结:

所以,我们在处理java的编码问题时,要分清楚三个概念:Java采用的编码:unicode,JVM平台默认字符集和外部资源的编码。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值