DBUnit导数据报表名超长
这几天在整理Sybse数据库的安装介质,安装介质中我们采用ant+dbunit来实现创建表和默认数据。以前我们在整理sql server和Oracle的安装介质时,没怎么遇到什么问题,但是在整理Sybase时却是步履维艰。为了以后的使用方便,这里做下记录。
本文使用的是Sybase是12.5.3。
一、 标识符最大长度为28的限制
[1] 错误信息如下:
BUILD FAILED D:\temp\EKPV7.0_defaultDB\build.xml:50: org.dbunit.DatabaseUnitException: java.s ql.SQLException: The identifier that starts with '"XWCMUSERATTENTIONCHANNELANDD' is too long. Maximum length is 28. |
[2] 对应的导入代码:
<table name="XWCMUSERATTENTIONCHANNELANDDOC"> <column>USERATTENTIONCHANNELANDDOCID</column> |
[3] 为什么?
我们都知道,为了支持多种数据库,表名和列名的设计的字符长度不要30个字符。Sybase使用手册中也说明了表名和列名最大支持30个字符。但是表名“XWCMUSERATTENTIONCHANNELANDDOC”的长度正好是30个字符,那为什么报超长了呢?
仔细留意下看看上面报的错误信息(注意错误信息中的红色双引号),在dbunit执行的时候实际上是计算了表“XWCMUSERATTENTIONCHANNELANDDOC”表名前和表名后的双引号,导致了表名的长度只能支持28个字符。
[4] 解决方案
通过查询dbunit官网,发现我们可以通过参数“dest.sql.escapePattern”来控制实现的,修改前的代码为:
dest.sql.escapePattern="?" |
修改后的正确代码为:
dest.sql.escapePattern="\"" |
官方说明解释“escapePattern”字符的说明:
Allows schema, table and column names escaping. The property value is an escape pattern where the ? is replaced by the name. For example, the pattern "[?]" is expanded as "[MY_TABLE]" for a table named "MY_TABLE". The most common escape pattern is "\"?\"" which surrounds the table name with quotes (for the above example it would result in "\"MY_TABLE\""). |
网址:http://www.dbunit.org/properties.html#escapepattern
二、 MBCS Parameter truncated
[1] 错误信息如下:
BUILD FAILED D:\temp\EKPV7.0_defaultDB\build.xml:50: org.dbunit.DatabaseUnitException: java.s ql.SQLException: MBCS Parameter truncated. |
[2] 错误分析
遇到这个错,我想第一件事就是需要先把这个错误是什么意思搞明白,这里的“BMCS”是“Multi-Byte Chactacter System,即多字节字符系统”的缩写。这个异常是说“多字节字符系统字段被截断了”,也就是说我们导入的数据中有数据内容超过了数据库中定义的字段长度。经过二分法,定位到哪条数据出错后,发现对应的字段在数据库中的长度并小于数据长度(Sybase我这里使用的是UTF-8编码,即使把数据长度*3 也是小于DB中定义的长度),很奇怪。为了能够验证问题,我把数据库中对应的字段类型设置为“text”,再次执行“antimportdata”,竟然还报同样的错,奔溃(text类型还能不够存储,扯淡了吧)!
没办法,怀疑是ant时使用的驱动jar包问题,把“jtds.jar”升级到1.2版本(以前使用是1.1版本),一切执行成功!
[3] 尝试查找jtds.jar的问题
把ant依赖的jar用winrar解压成class文件,接着利用editplus的多文件搜索功能,搜索“MBCS Parametertruncated.”,结果发现在文件“dependlib\jtds-1.1\net\sourceforge\jtds\jdbc\Messages.properties”文件中有下面内容的定义(见红色内容):
…… error.generic.timeout=The query has timed out. error.generic.truncmbcs=MBCS Parameter truncated. …… |
再通过editplus搜索“error.generic.truncmbcs”,发现在类“dependlib\jtds-1.1\net\sourceforge\jtds\jdbc\TdsData.class”文件中有这个引用,而且只搜索到这一处,猜测可能是这个地方引起的。相关的代码反编译后如下(注意红色地方):
static void writeTds5Param(RequestStream out, CharsetInfo charsetInfo, ParamInfo pi) throws IOException, SQLException { byte[] buf; if (pi.charsetInfo == null) { pi.charsetInfo = charsetInfo; } switch (pi.tdsType) { case 39: if (pi.value == null) { out.write(0); return; } buf = pi.getBytes(pi.charsetInfo.getCharset());
if (buf.length == 0) { buf = new byte[1]; buf[0] = 32; }
if (buf.length > 255) { //1.1版本对于varchar类型,如果导入的value值经过编码后的长度超过255则报错。1.2版本中,调整了实现方案,调整为流的方式输入 throw new SQLException(Messages.get("error.generic.truncmbcs"), "HY000"); }
out.write((byte)buf.length); out.write(buf); …… |
[4] 尝试查找jtds.jar的问题
我在1.1版本的jtds.jar和1.2版本的ParamInfo.getBytes方法中增加调试信息,分别打印当前的value和编码,可以看出1.2版本中对于长一点的字符串(varchar)都调整为了“BufferedReader”或者其他的流形式了。
由于输出结果比较多,输出结果放到附件中。