作者:Willam2004
引言:
做程序开发经常会与数据库打交道,Ubuntu下连接Oracle数据库的工具也不少,如:SQuirreL SQL Client,SQLDeveloper等。但这些工具连接我们公司的数据库查询中文字符串时都是乱码。上网查了下(http://fanqiang.chinaunix.net/db/oracle/2001-04-16/1166.shtml),主要是因为服务器的字符集编码与本地客户端的编码不一致。执行:
select * from V$NLS_PARAMETERS
发现:NLS_CHARACTERSET 为"US7ASCII",说明oracle安装的字符集为ISO-8859-1,而我们访问的应用客户端形式多为GBK编码格式。但在我们的web应用中,对于中文显示却是正常的。是因为我们通过一种jdbcproxy包进行了编码转换,如配置:
<bean id="unpooledDataSource" class="com.mchange.v2.c3p0.DriverManagerDataSource"> <property name="driverClass"> <value>com.alibaba.china.jdbc.SimpleDriver</value> </property> <property name="jdbcUrl"> <value>jdbc:oracle:thin:@xx.xx.xx.xx:1521:xx</value> </property> <property name="properties"> <props> <prop key="user">xxx</prop> <prop key="password">xxx</prop> <prop key="bigStringTryClob">true</prop> <prop key="clientEncoding">GBK</prop> <prop key="serverEncoding">ISO-8859-1</prop> </props> </property> </bean>
从配置可以看到,SimpleDriver是实现Driver接口的实现类,但真正的驱动程序的注册还是依赖Oracle的驱动程序的实现。其中最关键的配置参数:clientEncoding,serverEncoding,前者是指定客户端的字符集编码,serverEncoding是指定服务器端字符集编码。clientEncoding需要与本地的字符集要一致,serverEncoding与oracle的字符集要一致。
解决方案:
在SQuirreL SQL Client 可以指定数据库驱动程序,将jdbcproxy和oracle dirver的jar包添加进去(jdbcproxy依赖oracle driver包),但添加后,查询中文字符仍然乱码。
不行是因为应用通过spring注入方式将clientEncoding和serverEncoding进行了注入,在SQuirrel SQL Client没有进行指定。接下来很简单了,做一个jdbc-proxy的patch包,增加如果默认没有指定clientEncoding和serverEncoding,那么设定clientEncoding=GBK,serverEncoding=ISO-8859-1。
重新加入jdbcproxy,中文字符正常显示!
原理:
jdbcproxy最关键的地方,是通过代理模式,对jdbc中的各个接口,如Connection,ResultSet,Statement等,增加了CharsetParam和CharsetConvert进行字符编码的转换,而字符编码转换的核心却是非常简单的:
编码:
String newString = new String(oldstring.getBytes(clientEncoding),serverEncoding)
解码:
String newString = new String(oldstring.getBytes(serverEncoding),clientEncoding)