日期:2014-05-16  浏览次数:20558 次

生产环境下 数据库乱码
背景:
数据库的client,connection等编码都是latin1,表的编码是utf-8.
开发环境是eclipse,默认编码是utf8.
这种方式下在linux命令行下获取中文数据正常,但是java的jdbc获取数据是乱码。(以前是用c获取的数据,现在要改成java获取数据)


在java的jdbc中假设获取数据sql 为select field from table ;乱码
可以修改sql语句为
select convert(unhex(hex(convert(field  using latin1))) using utf8) as content from table;
这样就可以正常显示。
同样如果你的生产库也是乱码同样可以用这个方法获取正常编码。(编码方式根据生产库修改)。

好,第一步解决了。可问题是,我们这的库很多,而且还是分布式的,并且字段也很多。不可能在写sql的时候每个字段都加上这个转化器。所以可否将这个转化放到java中。


于是从网上找来了字符串转化为16进制以及16进制转化为字符串方法:
private static String hexString = "0123456789ABCDEF";

	/*
	 * 将字符串编码成16进制数字,适用于所有字符(包括中文)
	 */
	public static String encode(String str) throws Exception {
		// 根据默认编码获取字节数组
		byte[] bytes = str.getBytes("utf-8");
		StringBuilder sb = new StringBuilder(bytes.length * 2);
		// 将字节数组中每个字节拆解成2位16进制整数
		for (int i = 0; i < bytes.length; i++) {
			sb.append(hexString.charAt((bytes[i] & 0xf0) >> 4));
			sb.append(hexString.charAt((bytes[i] & 0x0f) >> 0));
		}
		return sb.toString();
	}

	/*
	 * 将16进制数字解码成字符串,适用于所有字符(包括中文)
	 */
	public static String decode(String bytes) {
		ByteArrayOutputStream baos = new ByteArrayOutputStream(bytes.length() / 2);
		// 将每2位16进制整数组装成一个字节
		for (int i = 0; i < bytes.length(); i += 2)
			baos.write((hexString.indexOf(bytes.charAt(i)) << 4 | hexString.indexOf(bytes.charAt(i + 1))));
		return new String(baos.toByteArray());
	}

自己又写了个convert方法:
	/** 转化 */
	private static String convert(String str, String fromCharset, String charset) throws Exception {
		return new String(str.getBytes(fromCharset), charset);
	}

由于latin1对应的编码为ios-8859-1,但是此编码缺失字符较多。所以使用 Windows-1252编码。
(此处普及下编码没一种编码实际上对应的是一个矩阵中的内容,即这个矩阵有内容的就可以正确解析为字符,如果没有则解析失败关于ios-8859-1和Windows-1252的编码情况以及范围可以参考一下http://en.wikipedia.org/wiki/Windows-1252 和http://en.wikipedia.org/wiki/ISO/IEC_8859-1 )
执行下
convert(decode(encode(convert(a, "utf8", "utf8"))), "Windows-1252", "utf8")

来对比下结果
百姓身边:北京市出台全国首个职工发展五年规划,明确提出反对任何形式的就业歧视,有关编制内外同工不同酬造成的不公平现象,有望3年内得到遏制.

百姓身边:北京市出???全国首个???工???展五年规划,明确???出???对任何形??的就业歧视,有关编制内外???工?????酬造??的??公平现象,有望3年内得到???制.


根据上面的情况进行转化吧。
结果还算乐观,但是由于编码的有些位缺失,所以还是有部分乱码。所以下一步就是看那种编码能更全面的包括所以字符。