【已解决】mysql+unitils用@DataSet,抛NoSuchColumnException
2013-11-02 00:00
387 查看
是unitils的一个bug。
使用mysql,用@DataSet注入测试数据时,会抛出org.dbunit.dataset.NoSuchColumnException。
起因是新版本的dbunit(目前是2.4.9)细化了各种数据库的MetadataHandler的处理,为每一种数据库提供了一个MetadataHandler,如MySqlMetadataHandler,Db2MetadataHandler等。而unitils并没有升级(快两年没更新了,还会更新吗?),仍然使用dbunit提供的DefaultMetadataHandler。这个DefaultMetadataHandler并不能很好的处理各个数据库之间的不同,所以会导致兼容问题。
有一种解决方案是将dbunit降级成2.4.2版本,虽然能解决这个问题,但是会引入新的问题。如果在数据XML文件中写入同一个表的两条数据,如:
则会抛出org.dbunit.database.AmbiguousTableNameException
问题的详细描述见此贴http://zfanxu.iteye.com/blog/1508339
真的很感谢这个作者抛砖引玉提供了很多线索。
我不是很喜欢直接修改第三方开源库的源码,缺点就不说了,所以想用扩展的方式解决这个问题。
首先通过阅读源码发现,dbunit提供了MySqlConnection,OracleConnection等等类。而dbunit则是定义了一个他们的兄弟类DbUnitDatabaseConnection,所有的dbunit的数据库连接都从这个类生成,这个类自然不包括各个数据库的方言之类的东西。
再看MySqlConnection,其实里面也没什么东西,就是向config里set了两个属性
所以关键点就在这里,只要能在从unitils得到connection之前把这两个属性set进去,就可以了。
再看unitils源码,得到数据库连接的方法是DbUnitModule的getDbUnitDatabaseConnection方法。那么只要新建一个类,覆盖这个方法,在super之后将相应的属性set进去就可以了。
代码如下:
最后一步,使用新建的MySqlDbUnitModule替换默认的DbUnitModule。这个就比较简单了,在unitils.properties中加入:
ok,大功告成,不用修改源码的方式,而且还可以重构的更好一点。如使用反射支持不同的数据库,而不仅仅是Mysql,或者使用枚举,把所有的数据库类型和它相关的DataTypeFactory以及MetadataHandler映射好。
由于反射不能在编译期检查,所以我选择了第二种方式。我将MySqlDbunitModule重构成了ExtDbunitModule和SupportedDatabaseType两个类。并且在unitils.properties文件中重新定义了一个key,DbUnitModule.database.type,用于set数据库类型是MySql还是Oracle等,目前支持所有的dbunit支持的数据库类型。有兴趣请到git oschina直接下载源码。
http://git.oschina.net/terrymanu/miracle-framework/tree/master/miraclesea/test-base
使用mysql,用@DataSet注入测试数据时,会抛出org.dbunit.dataset.NoSuchColumnException。
起因是新版本的dbunit(目前是2.4.9)细化了各种数据库的MetadataHandler的处理,为每一种数据库提供了一个MetadataHandler,如MySqlMetadataHandler,Db2MetadataHandler等。而unitils并没有升级(快两年没更新了,还会更新吗?),仍然使用dbunit提供的DefaultMetadataHandler。这个DefaultMetadataHandler并不能很好的处理各个数据库之间的不同,所以会导致兼容问题。
有一种解决方案是将dbunit降级成2.4.2版本,虽然能解决这个问题,但是会引入新的问题。如果在数据XML文件中写入同一个表的两条数据,如:
<?xml version='1.0' encoding='UTF-8'?> <dataset> <t_role id="1" name="test1" version="0" /> <t_role id="2" name="test2" version="0" /> </dataset>
则会抛出org.dbunit.database.AmbiguousTableNameException
问题的详细描述见此贴http://zfanxu.iteye.com/blog/1508339
真的很感谢这个作者抛砖引玉提供了很多线索。
我不是很喜欢直接修改第三方开源库的源码,缺点就不说了,所以想用扩展的方式解决这个问题。
首先通过阅读源码发现,dbunit提供了MySqlConnection,OracleConnection等等类。而dbunit则是定义了一个他们的兄弟类DbUnitDatabaseConnection,所有的dbunit的数据库连接都从这个类生成,这个类自然不包括各个数据库的方言之类的东西。
再看MySqlConnection,其实里面也没什么东西,就是向config里set了两个属性
getConfig().setProperty(DatabaseConfig.PROPERTY_DATATYPE_FACTORY, new MySqlDataTypeFactory()); getConfig().setProperty(DatabaseConfig.PROPERTY_METADATA_HANDLER, new MySqlMetadataHandler());
所以关键点就在这里,只要能在从unitils得到connection之前把这两个属性set进去,就可以了。
再看unitils源码,得到数据库连接的方法是DbUnitModule的getDbUnitDatabaseConnection方法。那么只要新建一个类,覆盖这个方法,在super之后将相应的属性set进去就可以了。
代码如下:
public final class MySqlDbUnitModule extends DbUnitModule { @Override public DbUnitDatabaseConnection getDbUnitDatabaseConnection(final String schemaName) { DbUnitDatabaseConnection result = dbUnitDatabaseConnections.get(schemaName); if (null != result) { return result; } result = super.getDbUnitDatabaseConnection(schemaName); result.getConfig().setProperty(DatabaseConfig.PROPERTY_DATATYPE_FACTORY, new MySqlDataTypeFactory()); result.getConfig().setProperty(DatabaseConfig.PROPERTY_METADATA_HANDLER, new MySqlMetadataHandler()); return result; } }
最后一步,使用新建的MySqlDbUnitModule替换默认的DbUnitModule。这个就比较简单了,在unitils.properties中加入:
unitils.module.dbunit.className=com.miraclesea.test.database.module.MySqlDbUnitModule
ok,大功告成,不用修改源码的方式,而且还可以重构的更好一点。如使用反射支持不同的数据库,而不仅仅是Mysql,或者使用枚举,把所有的数据库类型和它相关的DataTypeFactory以及MetadataHandler映射好。
由于反射不能在编译期检查,所以我选择了第二种方式。我将MySqlDbunitModule重构成了ExtDbunitModule和SupportedDatabaseType两个类。并且在unitils.properties文件中重新定义了一个key,DbUnitModule.database.type,用于set数据库类型是MySql还是Oracle等,目前支持所有的dbunit支持的数据库类型。有兴趣请到git oschina直接下载源码。
http://git.oschina.net/terrymanu/miracle-framework/tree/master/miraclesea/test-base
相关文章推荐
- org.dbunit.dataset.NoSuchColumnException: t_role.ROLE_TYPE - (Non-uppercase input column: role_type
- [解决方法]org.dbunit.dataset.NoSuchTableException: Did not find table 'tab1' in schema 'null'
- mysql+dbunit 抛出NoSuchColumnException、DataSetException
- dbunit经典的NoSuchColumnException解决之道
- 解决网页元素无法定位(NoSuchElementException: Unable to locate element)的几种方法
- org.openqa.selenium.NoSuchElementException: Unable to locate element: 异常解决方法
- Mysql_connect报告”No such file or directory”错误的解决方法
- Exception 'yii\db\Exception' with message 'SQLSTATE[HY000] [2002] No such file or directory’错误的解决方法
- no such file to load — mysql错误解决
- android.database.sqlite.SQLiteException: table tb_diary2 has no column named recordPath 解决办法
- android.database.sqlite.SQLiteException: table tb_diary2 has no column named recordPath 解决办法
- mysql安装出现Errcode: 2 - No such file or directory错误的解决办法
- com.mysql.jdbc.exceptions.MySQLSyntaxErrorException: Unknown column"错误解决方
- 用xamarin开发android遇见 SQLite.SQLiteException: no such collation sequence: Id 解决方法
- ssm整合中出现illegalargumentexception、NosuchbeansException解决
- Mysql启动报错:Unit mysql.service failed to load: No such file or directory的解决办法
- mysql_connect报告”No such file or directory”错误的解决方法
- Android编程:解决异常“java.util.NoSuchElementException”
- 遭遇org.dbunit.dataset.NoSuchTableException
- "com.mysql.jdbc.exceptions.MySQLSyntaxErrorException: Unknown column"错误解决方法