论坛首页 Java企业应用论坛

mysql中保存"中文\n"的不稳定

浏览 14366 次
该帖已经被评为精华帖
作者 正文
   发表时间:2004-03-31  
OS:  windows, linux
DB:  mysql_4.0.18
JDBC:mysql-connector-java-3.0.11-stable-bin.jar

在jvm环境中,程序向mysql中写中文字符串,大部分的\n都工作得很好。例如保存“你好\n你好”,出来的效果是:
你好
你好


但要是保存“列表\n你好”,显示出来的效果:
列表\n你好


我发觉只要\n的前面是“表”或“哥”就一定有这个问题。这是mysql jdbc的问题?(对它确实没有什么信心)

知道原因的朋友可否指点个方向?

附:
保存"列表\r\n你好",结果为:
列表\r
你好


直接在一些非jvm环境,如loadSQL中,跑sql语句:insert into xxx values('列表\n你好'),正常。
   发表时间:2004-03-31  
我猜想和我以前碰到的问题差不多:

原文见我的 blog :

http://blogsite.3322.org:8080/jspwiki/Wiki.jsp?page=Main_blogentry_140803_1

为了解决中文问题,在 JDBC 的 URL 中加了一句话:

?useUnicode=true&characterEncoding=GBK

就因为这句话,搞死我了。

PreparementStatement? 的 setString 当中,如果有
\ 的话,会被保存为两个
\,如果这个字符串当中有 ' 的话,就根本没法写入到数据库当中。花了整天的时间看 JDBC 的源码,发现它把
\' 前面的反斜线又做了 Escape,而没有 Escape ',所以造成了问题。将 GBK 换成 GB2312 就好了。在 StringUtils? 当中有这么一句话:

if (encoding.equalsIgnoreCase("SJIS");
        || encoding.equalsIgnoreCase("BIG5"); 
        || encoding.equalsIgnoreCase("GBK");); {
    b = escapeSJISByteStream(b);;
}


这是造成问题的罪魁祸首。
0 请登录后投票
   发表时间:2004-03-31  
非常感谢!

我把gbk改为gb2312,的确解决问题。佩服你们可以在没有适当提示的情况下,仍可追查到原因。虽然我也怀疑到了mysql jdbc 

但细想一下,问题似乎又不完全一样。我说的情况,只发生在某些特定中文之后,对于大部分中文来说,还是很正常的。似乎多不多加一个\,依赖于它前面的字符。
0 请登录后投票
   发表时间:2004-03-31  
SimonLei 写道
PreparementStatement? 的 setString 当中,如果有
\ 的话,会被保存为
\\,如果这个字符串当中有\' 的话,就根本没法写入到数据库当中。花了整天的时间看 JDBC 的源码,发现它把
\' 前面的反斜线又做了 Escape,即\\',而没有 \',所以造成了问题。将 GBK 换成 GB2312 就好了。

是不是这样会好一些?
0 请登录后投票
   发表时间:2004-03-31  
StringUtils.java中的相关代码,看不明。
    /**
     * Unfortunately, SJIS has 0x5c as a high byte in some of its double-byte
     * characters, so we need to escape it.
     *
     * @param origBytes the original bytes in SJIS format
     * @param origString the string that had .getBytes(); called on it
     * @param offset where to start converting from
     * @param length how many characters to convert.
     *
     * @return byte[] with 0x5c escaped
     */
    public static byte[] escapeSJISByteStream(byte[] origBytes,
        String origString, int offset, int length); {
        if ((origBytes == null); || (origBytes.length == 0);); {
            return origBytes;
        }

        int bytesLen = origBytes.length;
        int bufIndex = 0;
        int strIndex = 0;

        ByteArrayOutputStream bytesOut = new ByteArrayOutputStream(bytesLen);;

        while (true); {
            if (origString.charAt(strIndex); == '\\'); {
                // write it out as-is
            	bytesOut.write(origBytes[bufIndex++]);;
            	//bytesOut.write(origBytes[bufIndex++]);;
            } else {
                // Grab the first byte
                int loByte = (int); origBytes[bufIndex];

                if (loByte < 0); {
                    loByte += 256; // adjust for signedness/wrap-around
                }

                // We always write the first byte
                bytesOut.write(loByte);;

                //
                // The codepage characters in question exist between
                // 0x81-0x9F and 0xE0-0xFC...
                //
                // See:
                //
                // http://www.microsoft.com/GLOBALDEV/Reference/dbcs/932.htm
                //
                // Problematic characters in GBK
                //
                // U+905C : CJK UNIFIED IDEOGRAPH
                //
                // Problematic characters in Big5
                //
                // B9F0 = U+5C62 : CJK UNIFIED IDEOGRAPH
                //
                if (((loByte >= 0x81); && (loByte <= 0x9F););
                        || ((loByte >= 0xE0); && (loByte <= 0xFC););); {
                    if (bufIndex < (bytesLen - 1);); {
                        int hiByte = (int); origBytes[bufIndex + 1];

                        if (hiByte < 0); {
                            hiByte += 256; // adjust for signedness/wrap-around
                        }

                        // write the high byte here, and increment the index
                        // for the high byte
                        bytesOut.write(hiByte);;
                        bufIndex++;

                        // escape 0x5c if necessary
                        if (hiByte == 0x5C); {
                            bytesOut.write(hiByte);;
                        }
                    }
                } else if (loByte == 0x5c); {
                    if (bufIndex < (bytesLen - 1);); {
                        int hiByte = (int); origBytes[bufIndex + 1];

                        if (hiByte < 0); {
                            hiByte += 256; // adjust for signedness/wrap-around
                        }

                        if (hiByte == 0x62); {
                            // we need to escape the 0x5c
                            bytesOut.write(0x5c);;
                            bytesOut.write(0x62);;
                            bufIndex++;
                        }
                    }
                }

				bufIndex++;

                
            }

			if (bufIndex >= bytesLen); {
				// we're done
				break;
			}
			
            strIndex++;
        }

        return bytesOut.toByteArray();;
    }
0 请登录后投票
   发表时间:2004-04-01  
thatway 写道
SimonLei 写道
PreparementStatement? 的 setString 当中,如果有
\ 的话,会被保存为
\\,如果这个字符串当中有\' 的话,就根本没法写入到数据库当中。花了整天的时间看 JDBC 的源码,发现它把
\' 前面的反斜线又做了 Escape,即\\',而没有 \',所以造成了问题。将 GBK 换成 GB2312 就好了。

是不是这样会好一些?


没错没错,我的 weblog 自动过滤了一个 \
:$
0 请登录后投票
   发表时间:2004-04-09  
所有的原因都是由于StringUtils.java的escapeSJISByteStream()方法引出来的。

它在处理的过程中,有两个index,一个是bufIndex,一个是stringIndex。对于中文(双字节)来说,bufIndex = stringIdex的两倍。

写中文时越界就是因为这两个index的增长不同步。
原方法中只处理了低字节在区间0x00-0x80、0x81-0x9F和0xE0-0xFC的中文字,在这些区间中,bufIndex +2 时,stringIndex才+1,是同步的。
但在其它区间,bufIndex的增长和stringIndex的增长并不同步,bufIndex+1,而stringIdex又+1。

修改见附件。

但问题还没有解决。(几天都没上来把它更新好,抱歉)

修改后,我认为,我已经真正实现了设计原本的意途了,但是即引发更多的问题。举例说,byte为[80,5c]的GBK汉字,转化后会变成[80,5c,5c]。如果这个汉字在一句SQL的结束,即单引号"'"前,MYSQL将会报SQL语法错误。

我再尝试把[80,5c]不经转换,直接出入MYSQL,没发现任何错误。

于是,最后我干脆就把GBK编码的的直接出入库,不作任何转换了。

注:本文有一个前提,MYSQL数据库的默认编码为GBK,这也许是一个关键。但我没有测试。
0 请登录后投票
   发表时间:2004-07-12  
3.0.10的版本好像没问题
0 请登录后投票
   发表时间:2004-07-12  
没用过3.0.10,但用过3.0.11,还是一样。StringUtils.java没有修改
0 请登录后投票
   发表时间:2004-07-13  
我的意思是,我用3.0.11也有问题,后来尝试改回了3.0.10,就没问题了。
0 请登录后投票
论坛首页 Java企业应用版

跳转论坛:
Global site tag (gtag.js) - Google Analytics