本文记录的是使用DBUnit测试框架进行数据库数据插入时,插入特殊字符失败的查错经历。希望能对向我这样的小白同学们在遇到类似问题时,能够有一些启发。
背景:
在写跟数据库交互模块的单元测试,数据库表中的ext字段,需要先写入数据,然后再读取出来,进行处理。ext字段格式是key1CTRL^Dvalue1CTRL^CKey2CTRL^Dvalue2。使用DBUnit框架来做单元测试,DBUnit是一个基于junit扩展的数据库测试框架。此次项目里插入数据库的数据是以xml形式的文件来组织的。xml文件的部分内容如下

<?xml version="1.0" encoding="utf-8"?>
<dataset>
<feed_item_0007
id="323723909"
biz_number="11223345"
ext="item_price\u0003498.00\u0002postage\u000310.00\u0002location\u0003广州深圳\u0002properties\u0003186026840:125200612;6939376:922305\u0002"
/>
</dataset>

在Java中,CTRL^D的值是(char)4,CTRL^C的值是(char)3。此处普及下Java代码中字符串\u0003的意思,就是说Unicode值(char)3转义之后的值。在单元测试中,发现数据库中读取出的数据,本来一个字符 CTRL^C 即 \u0003 变成了6个字符,分别是\,u,0,0,0,3.

排查问题的过程

既然数据库里读取出的值不对,说明插入的值就是错的。首先不太了解Java,没有仔细看import到单元测试里的包,没有发现使用了junit框架和DBUnit。导致盲目找了一会儿同事开发的DBUnitBaseTest这个单元测试基类的问题,认为就是转码的问题。无果,后来看到了这个基类DBUniteBaseTest的源码,才知道有DBUnit这个东东,而且发现基类没做什么特殊处理,就是根据配置文件初始化DataSource,然后根据xml数据文件向数据库中对应表插入数据的过程。

后来在google里搜索,用的关键词就是dbunit \u0003 之类的,太具体了,导致没有查到太多相关的有用信息。一直苦于找不到解决问题的思路。
后来有同事提醒可以用CDATA,查了一下CDATA的用法,有了一些思路。

"CDATA是在XML文档里面使用的关键字,用来告诉XML解析器,这部分内容不用解析,是给其他程序用的,比如JAVASCRIPT等等。在XML文档中的所有文本都会被解析器解析,只有在CDATA部件之内的文本会被解析器忽略。"

后来又从上面的搜索结果的网页里看到了一个有用的东东:numeric character reference.

Because XML syntax uses some characters for tags and attributes it is not possible to directly use those characters inside XML tags or attribute values. To include special characters inside XM files you must use the numeric character reference instead of that character. The numeric character reference must be UTF-8 because the supported encoding for XML files is defined in the prolog as encoding=“UTF-8” and should not be changed.

The numeric character reference uses the format:

&#nn; decimal form

&#xhh; hexadeciaml form

于是就有了以下的方案:
1.尝试直接写 \u0004的 numeric character,就是 &#4; 失败,报的错误是: Character reference "&#4" is an invalid XML character
2.\u0004中,只把 \ 用numeric character代替了,即\ u0004 这个方式仍然是6个字符,跟直接写 \u0004 一样的效果
3. 使用 CDATA: ext=<![CDATA["postage\u000410.0\u0003"]]> 发现写法可能不对,报错是xml的格式出错。

这个时候,感觉自己快接近真相了,就是感觉每次搜索\u0004相关的东西,范围太小了,不太能找到问题的答案。后来跟同事聊这个问题,同事提到就是这些控制字符没有正确编码,一下子就把我点醒了。直接搜 does xml support control characters,有如下发现:

Specifically, 0x1-0x1F and 0x7F-0x9F must be encoded as escapes in XML 1.1. The former were forbidden and the latter were optionally not-escaped in 1.0.

所以可以看到,采用方案1时,由于XML1.0不支持这几个控制字符,所以仍然报错,而且是说&#4这个字符是非法的XML字符。从上面的搜索结果里看,XML 1.1 支持这几个控制字符,于是很开心的把xml文件中的xml版本由1.0改成1.1,结果还是报错了:

org.dbunit.dataset.DataSetException: Line 1: XML version "1.1" is not supported, only XML 1.0 is supported.

最后使出了简单粗暴的解决办法:对于这张表的这个字段,直接使用DataSource, 然后用Statement执行sql语句来进行数据的更新,更新为我们想要的字段。

PS:后来又遇到了在java的properties文件里,如果有中文,程序中解析出来是乱码的问题。查看了一下同事写的单元测试的基类DBUnitTest的代码,发现properties文件是通过Properties类来加载的 prop.load(new FileInputStream(file))。搜索了一下Properties类的load函数的定义,发现是因为

The input stream is in a simple line-oriented
format as specified in
load(Reader) and is assumed to use
the ISO 8859-1 character encoding;

使用DBUnit框架数据库插入特殊字符失败的查错经历的更多相关文章

  1. 数据库 插入时 碰到NULL报错判断的一种方法(技巧)

    //public static object ToDBNull(object value) 判断插入数据的时候个别参数不能为空的时候做的判断方法 //{ // if (value == null) / ...

  2. 数据库插入数据失败,log提示不能将值 NULL 插入列 'id'

    已经记不住具体的log信息了,意思就是ID如果没有设置为自增长的情况下就不能插入数据,而建表时ID字段是设置为"not null",所以就不能顺利插入数据. 解决方法有两种: ①建 ...

  3. VS Code编写Python3 insert 数据库插入无效也不报错的坑~.~

    标题最近在开发中需要用到web端开发工具.需要用python工具.偶然发现微软的良心之作:Visual Studio Code,这个大小才几十兆的轻量级代码编辑器,功能却是重量级的,通过插件的方法,, ...

  4. Mybatis 向MySql数据库插入带有日期类型字段的数据

    我们的实体类里面一个字段的日期类型是util.Date,在向数据库插入该实体时会报错,说是 日期哪个字段 Data truncation.所以需要做些更改在mybatis的MAPPER映射文件中对插入 ...

  5. 十三、CI框架之数据库插入操作

    一.CI的数据库插入代码如下: 二.数据库原数据如下: 三.访问网站之后,会显示相关输出 四.我们查看数据库,会增加一条数据 不忘初心,如果您认为这篇文章有价值,认同作者的付出,可以微信二维码打赏任意 ...

  6. uct框架数据库sql文件导入错误之 sql_mode

    uct框架在导入sql文件时可能会出现一种错误 ERROR 1101 (42000): BLOB/TEXT column 'brief' can't have a default value 这是由于 ...

  7. AGS中通过FeatureServer插入数据失败、插入数据在WMTS请求中无法显示以及version概念的讨论

    文章版权由作者李晓晖和博客园共有,若转载请于明显处标明出处:http://www.cnblogs.com/naaoveGIS/. 1.背景 在多个项目中,当我方接口给其他部门人员使用时出现了插入数据失 ...

  8. Laravel框架数据库CURD操作、连贯操作使用方法

    Laravel框架数据库CURD操作.连贯如何来操作了这个操作性是非常的方便简单了我们在这里来为各位介绍一篇相关的教程,具体的细节步骤如下文介绍.   Laravel是一套简洁.优雅的PHP Web开 ...

  9. Laravel框架数据库CURD操作、连贯操作

    这篇文章主要介绍了Laravel框架数据库CURD操作.连贯操作.链式操作总结,本文包含大量数据库操作常用方法,需要的朋友可以参考下 一.Selects 检索表中的所有行 $users = DB::t ...

随机推荐

  1. VMware克隆SUSE网卡配置

    1.配置DNS vim /etc/resolv.conf domain sitenameserver 202.98.0.682.配置网关 vim /etc/sysconfig/network/rout ...

  2. vpython初探

    vpython 是python默认的3D模块,和python有一样的风格.与PyOpenGL相比,容易上手. vpython下载:vpython的官网(www.vpython.org).顺便说一句,官 ...

  3. 云存储的那些事(2)——数据分布算法CRUSH

    在分布式系统中,数据最终还是要存储到物理设备上的,ceph的底层设备抽象角色是OSD,那么数据是如何被决定放在哪块OSD上的,答案就是CRUSH算法. 关键字:CRUSH.一致性hash.ceph数据 ...

  4. interactivePopGestureRecognizer属性

    苹果一直都在人机交互中尽力做到极致,在iOS7中,新增加了一个小小的功能,也就是这个api:self.navigationController.interactivePopGestureRecogni ...

  5. ueditor问题简记录

    一.百度ueditor下载地址:http://ueditor.baidu.com/website/download.html. uBuilder下载,个人选了一些自用的,.net的,但是很奇怪下载响应 ...

  6. 类Arrays

    package p2; import java.util.Arrays; import java.util.List; public class ArraysDemo { public static ...

  7. 14.Xcode8imageview图片圆角不显示的bug

    第一种方法: 在imageView调用clipToBounds的之前,[super awakeFromNib]之后,加上[self.contentView layoutIfNeeded];就可以了,反 ...

  8. python 使用字符串名调用类以及调用类方法名

    在python中,有时调用者仅知道类名和类方法,不负责实际的函数调用,而是将要调用的类名和类方法告诉一个中间函数,由中间函数负责实际调用函数.中间函数需以被告知的字符串调用类和类方法.         ...

  9. windows下监测tomcat7内存使用情况

    在conf里面的server-user文件里添加 <tomcat-users> <role rolename="admin-gui"/> <user ...

  10. Spring学习笔记 6. 尚硅谷_佟刚_Spring_Bean 之间的关系

    1,继承关系 首先从简单的代码来看,有一个Address类,配置文件有两个bean (1)Address类 package com.zsq; public class Address { privat ...