org.dbunit.database.AmbiguousTableNameException 終極解決方案

項目的單元測試用到了dbunit進行數據組裝,最近遇到了org.dbunit.database.AmbiguousTableNameException: XXXX數據庫表 問題,在網上查找了不少資料,最終還是通過同事的幫助(數據庫工程師)一起把問題解決。網上通常的解決方案是對connection增加schema問題即可解決,原因是不同的schema可能會遇到相同的表名,導致拋出錯誤。 但是這個問題好解決(schema設置爲null也可以解決),如下代碼: properties.put(DatabaseConfig.FEATURE_QUALIFIED_TABLE_NAMES, "true");databaseConnection.getConfig().setPropertiesByString(stringProperties) 即可解決。 (由於導入數據庫的一個xml裏有不同的schema,所有connction不能指定schema)

那問題是什麼呢?  由於是測試數據庫,最後把"XXXX數據庫表"刪除掉,問題解決。最後通過數據庫工程師分析,通過select * from dba_tables where owner='schmae' and table_name='XXXX數據庫表'  可以查詢出兩條記錄,可能是oracle數據庫的問題, 從而可推出dbunit源代碼裏(“罪魁禍首”代碼)應該是通過此sql語句進行預加載的,由於有兩條重複的表,導致報錯。所以數據庫工程師將此“垃圾表”清除掉,問題解決。

問題整理:

1.dbunit問題的核心代碼如下:

   private void initialize() throws DataSetException
    {
        logger.debug("initialize() - start");

        if (_tableMap != null)
        {
            return;
        }

        try
        {
            logger.debug("Initializing the data set from the database...");

            Connection jdbcConnection = _connection.getConnection();
            DatabaseMetaData databaseMetaData = jdbcConnection.getMetaData();

            String schema = _connection.getSchema();

            if(SQLHelper.isSybaseDb(jdbcConnection.getMetaData()) && !jdbcConnection.getMetaData().getUserName().equals(schema) ){
                logger.warn("For sybase the schema name should be equal to the user name. " +
                        "Otherwise the DatabaseMetaData#getTables() method might not return any columns. " +
                "See dbunit tracker #1628896 and http://issues.apache.org/jira/browse/TORQUE-40?page=all");
            }

            DatabaseConfig config = _connection.getConfig();
            String[] tableType = (String[])config.getProperty(DatabaseConfig.PROPERTY_TABLE_TYPE);
            IMetadataHandler metadataHandler = (IMetadataHandler) config.getProperty(DatabaseConfig.PROPERTY_METADATA_HANDLER);

            ResultSet resultSet = metadataHandler.getTables(databaseMetaData, schema, tableType);

            if(logger.isDebugEnabled())
            {
                logger.debug(SQLHelper.getDatabaseInfo(jdbcConnection.getMetaData()));
                logger.debug("metadata resultset={}", resultSet);
            }

            try
            {
                OrderedTableNameMap tableMap = super.createTableNameMap();
                while (resultSet.next())
                {
                    String schemaName = metadataHandler.getSchema(resultSet);
                    String tableName = resultSet.getString(3);

                    if(_tableFilter != null && !_tableFilter.accept(tableName))
                    {
                        logger.debug("Skipping table '{}'", tableName);
                        continue;
                    }
                    if(!_oracleRecycleBinTableFilter.accept(tableName))
                    {
                        logger.debug("Skipping oracle recycle bin table '{}'", tableName);
                        continue;
                    }


                    QualifiedTableName qualifiedTableName = new QualifiedTableName(tableName, schemaName);
                    tableName = qualifiedTableName.getQualifiedNameIfEnabled(config);

                    // Put the table into the table map
                    tableMap.add(tableName, null);
                }

                _tableMap = tableMap;
            }
            finally
            {
                resultSet.close();
            }
        }
        catch (SQLException e)
        {
            throw new DataSetException(e);
        }
    }

分析:

1.ResultSet resultSet = metadataHandler.getTables(databaseMetaData, schema, tableType); 

oracle用戶下指定的schema的表可全部查詢處理(如果schema爲null,則可查詢所有權限的表)

2.tableMap.add(tableName,null)
此add方法會先將map裏是否有重複的schema.table ,如果有則會拋出 
org.dbunit.database.AmbiguousTableNameException: XXXX數據庫表 異常。
3.通過select * from dba_tables where owner='schema' and table_name='XXXX數據庫表' 分析,有兩條記錄(一個大寫的表,一個是小寫的表),刪除掉一個解決。
刨根問底:
爲什麼會出現數據庫裏有兩條表的記錄呢? 上網查詢後得知,有個笨蛋用戶在建表時,通過雙引號建的表,比如 create table "XXX數據庫表",建好表後估計是發現查不到此表,然後又重新建了一個,最終導致Exception. 


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章