无法使用 JDBC 解析文件

Cannot parse file using JDBC

我正在尝试解析管道分隔文件并将字段插入 table。当我启动应用程序时,我的数据库中没有任何反应。我的数据库有 4 列(account_name、command_name 和 system_name、CreateDt)。我正在解析的文件在第一行有日期,然后是额外的数据。接下来的行我只需要每个字段中的前 3 个字段,其余的是额外的数据。最后一行是行数。我跳过了插入日期,因为现在但我想在至少能够插入前 3 个字段后回到它。我在解析文件和将数据存储在数据库中的经验很少,并且已经查看了 jdbc 示例以达到这一点,但我正在努力并确信有更好的方法。

文件示例

20200310|extra|extra|extra||
Mn1223|01192|windows|extra|extra|extra||
Sd1223|02390|linux|extra|extra|extra||
2

table格式

account_name      command_name   system_name    createDt
Mn1223            01192          windows        20200310
Sd1223            02390          linux          20200310

解析并插入数据库的代码

public List insertZygateData (List<ZygateEntity> parseData) throws Exception {
        String filePath = "C:\DEV\Test_file.xlsx";


        List<String> lines = Files.readAllLines(Paths.get(filePath));

        // remove date and amount
        lines.remove(0);
        lines.remove(lines.size() - 1);

        for (ZygateEntity zygateInfo : parseData){
                    new MapSqlParameterSource("account_name", zygateInfo.getAccountName())
                            .addValue("command_name", zygateInfo.getCommandName())
                            .addValue("system_name", zygateInfo.getSystemName())
                            .getValues();

        }
        return lines.stream()
                .map(s -> s.split("[|]")).map(val -> new ZygateEntity(val[0],val[1],val[2])).collect(Collectors.toList());


    }


    public boolean cleantheTable() throws SQLException {

        String sql = "INSERT INTO Landing.midrange_xygate_load (account_name,command_name,system_name)"+
                "VALUES (:account_name,:command_name,:system_name)";

        boolean truncated = false;
        Statement stmt = null;
        try {
            String sqlTruncate = "truncate table Landing.midrange_xygate_load";
            jdbcTemplate.execute(sqlTruncate);
            truncated = true;

        } catch (Exception e) {
            e.printStackTrace();
            truncated = false;
            return truncated;
        } finally {
            if (stmt != null) {
                jdbcTemplate.execute(sql);
                stmt.close();
            }

        }
        log.info("Clean the table return value :" + truncated);
        return truncated;
    }
}

Entity/Model

public ZygateEntity(String accountName, String commandName, String systemName){
        this.accountName=accountName;
        this.commandName=commandName;
        this.systemName=systemName;
    }

   //getters and setters
    @Override
    public String toString() {
        return "ZygateEntity [accountName=" + accountName + ", commandName=" + commandName + ", systemName=" + systemName + ", createDt=" + createDt +"]";
    }
}

看看您提供的内容,您似乎有一堆混乱的代码位,虽然其中大部分都在那里,但并不是全部都在那里,而且顺序也不完全正确。

为了获得某种清晰度,请尝试将您正在做的事情分解成单独的步骤,并制定一个专注于每个步骤的方法。特别是,你写

Im trying to parse a pipe delimited file and insert fields into a table

这自然分为两部分:

  • 解析竖线分隔文件,并且
  • 正在将字段插入 table。

对于第一部分,您的 insertZygateData 方法中似乎已经包含了大部分内容。特别是,这一行将文件的所有行读入列表:

    List<String> lines = Files.readAllLines(Paths.get(filePath));

这些行然后从行列表中删除第一行和最后一行:

    // remove date and amount
    lines.remove(0);
    lines.remove(lines.size() - 1);

然后你有一些看起来有点不合适的代码:这似乎与插入数据库有关,但我们还没有创建我们的 ZygateEntity 对象列表,因为我们没有'还没有读完文件。让我们暂时把这个 for 循环放在一边。

最后,我们获取我们读取的行列表,使用管道拆分它们,从部分创建 ZygateEntity 个对象并创建这些对象的 List,然后我们 return.

    return lines.stream()
            .map(s -> s.split("[|]")).map(val -> new ZygateEntity(val[0],val[1],val[2])).collect(Collectors.toList());

把这些放在一起,我们有一个有用的方法来解析文件,完成任务的第一部分:

    private List<ZygateEntity> parseZygateData() throws IOException {
        String filePath = "C:\DEV\Test_file.xlsx";

        List<String> lines = Files.readAllLines(Paths.get(filePath));

        // remove date and amount
        lines.remove(0);
        lines.remove(lines.size() - 1);

        return lines.stream()
                .map(s -> s.split("[|]")).map(val -> new ZygateEntity(val[0],val[1],val[2])).collect(Collectors.toList());
    }

(当然,我们可以为要读取的文件路径添加一个参数,但为了让某些东西正常工作,坚持使用当前的硬编码文件路径是可以的。)


所以,我们得到了 ZygateEntity 个对象的列表。我们如何编写方法将它们插入数据库?

我们可以在您的代码示例中找到一些我们需要的成分。首先,我们需要 SQL 语句来插入数据。这是在您的 cleanThetable 方法中:

    String sql = "INSERT INTO Landing.midrange_xygate_load (account_name,command_name,system_name)"+
            "VALUES (:account_name,:command_name,:system_name)";

然后我们有这个循环:

    for (ZygateEntity zygateInfo : parseData){
                new MapSqlParameterSource("account_name", zygateInfo.getAccountName())
                        .addValue("command_name", zygateInfo.getCommandName())
                        .addValue("system_name", zygateInfo.getSystemName())
                        .getValues();
    }

此循环从每个 ZygateEntity 对象创建一个 MapSqlParameterSource,然后通过调用 getValues() 方法将其转换为 Map<String, Object>。但是它对这个值没有任何作用。实际上,您正在创建这些对象并在不对它们进行任何操作的情况下再次删除它们。这不理想。

A MapSqlParameterSource 与 Spring NamedParameterJdbcTemplate 一起使用。您的代码提到了一个 jdbcTemplate,它似乎是 class 中的一个字段,用于解析数据并插入数据库,但您没有显示此 class 的完整代码。我将不得不假设它是 NamedParameterJdbcTemplate 而不是 'plain' JdbcTemplate.

A NamedParameterJdbcTemplate 包含一个方法 update,它接受一个 SQL 字符串和一个 SqlParameterSource。我们有一个 SQL 字符串,我们正在创建 MapSqlParameterSource 对象,因此我们可以使用它们来执行插入。创建这些 MapSqlParameterSource 对象之一只是为了将其转换为地图没有太多意义,所以让我们删除对 getValues().

的调用

所以,我们现在有一个将数据插入数据库的方法:

public void insertZygateData(List<ZygateEntity> parseData) {
    String sql = "INSERT INTO Landing.midrange_xygate_load (account_name,command_name,system_name)"+
            "VALUES (:account_name,:command_name,:system_name)";

    for (ZygateEntity zygateInfo : parseData){
        SqlParameterSource source = new MapSqlParameterSource("account_name", zygateInfo.getAccountName())
                .addValue("command_name", zygateInfo.getCommandName())
                .addValue("system_name", zygateInfo.getSystemName());
        jdbcTemplate.update(sql, source);
    }
}

最后,让我们来看看你的cleanThetable方法。与其他任务一样,让我们​​专注于一个任务:目前您正在尝试从 table 中删除数据,然后以相同的方法插入它,但我们只关注它关于删除数据,因为我们现在有了插入数据的方法。

我们不能立即删除 String sql = ... 行,因为代码中的 finally 块使用了它。如果 stmt 不为空,则您尝试 运行 INSERT 语句然后关闭 stmt.

但是,stmt 从未被赋予 null 以外的任何值,因此它仍然是 nullstmt != null 因此总是 false,因此 INSERT 语句永远不会 运行。您的 finally 块永远不会做任何事情,因此您最好将其完全删除。随着 finally 块消失,您还可以摆脱局部变量 stmtsql 字符串,给我们留下一个方法,其重点是 t运行cate table:

public boolean cleantheTable() throws SQLException {
    boolean truncated = false;
    try {
        String sqlTruncate = "truncate table Landing.midrange_xygate_load";
        jdbcTemplate.execute(sqlTruncate);
        truncated = true;

    } catch (Exception e) {
        e.printStackTrace();
        truncated = false;
        return truncated;
    }
    log.info("Clean the table return value :" + truncated);
    return truncated;
}

我将由您来编写调用这些方法的代码。我为此编写了一些代码,它 运行 成功地插入到数据库中。


因此,总而言之,没有数据被写入您的数据库,因为您从未调用数据库来插入任何数据。在您的 insertZygateData 方法中,您正在创建参数源对象但没有对它们做任何有用的事情,而在您的 cleanThetable 方法中,看起来您正在尝试插入数据,但是您的行 jdbcTemplate.execute(sql) 从未尝试这样做 运行。即使 stmt 不为空,这一行也不会起作用,因为您没有在任何地方传递参数值:您会从数据库中得到一个异常,因为它会期望参数值,但您永远不会给了它。

希望我的解释能为您提供一种让代码正常工作的方法,并帮助您理解为什么它不能正常工作。