无法使用JDBC解析文件

问题描述 投票:0回答:1

我正在尝试解析管道分隔文件并将字段插入表中。当我启动应用程序时,数据库中什么也没有发生。我的数据库有4列(account_name,command_name和system_name,CreateDt)。我正在解析的文件的第一行中有日期,然后是其他数据。我之后的行仅需要前三个字段,其余的都是额外数据。最后一行是行数。我略过了插入日期,因为现在,但想至少在能够插入前3个字段后再返回。我几乎没有解析文件并将数据存储在DB中的经验,并仔细研究了jdbc示例以了解这一点,但是我一直在挣扎,并且肯定有更好的方法。

文件示例

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

表格格式

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;
    }
}

实体/模型

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 +"]";
    }
}
java spring-boot jdbc spring-jdbc delimited-text
1个回答
0
投票

[看一下您提供的内容,似乎您杂乱无章地收集了一些代码,虽然其中大部分都在那里,但并不是全部都存在,也不是全部都以正确的顺序排列。

为了获得某种程度的清晰度,请尝试将您要执行的操作分解为单独的步骤,并有一种方法专注于每个步骤。特别是你写

我正在尝试解析管道分隔文件并将字段插入表中

这自然分为两部分:

  • 解析管道分隔的文件,然后
  • 将字段插入表中。

对于第一部分,您似乎已经在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 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();
    }

此循环从每个MapSqlParameterSource对象中创建一个MapSqlParameterSource,然后通过调用ZygateEntity方法将其转换为Map<String, Object>。但是,此值不起作用。实际上,您正在创建这些对象,并且无需对其进行任何操作即可再次摆脱它们​​。这不理想。

A getValues()与弹簧MapSqlParameterSource一起使用。您的代码中提到了NamedParameterJdbcTemplate,它似乎是类中的一个字段,用于解析数据并将其插入数据库中,但是您并未显示此类的完整代码。我将不得不假设它是NamedParameterJdbcTemplate而不是'普通'jdbcTemplate

NamedParameterJdbcTemplate包含采用SQL字符串和JdbcTemplate的方法NamedParameterJdbcTemplate。我们有一个SQL字符串,并且正在创建update对象,因此我们可以使用它们执行插入。创建这些SqlParameterSource对象之一只是为了将其转换为地图并没有太多意义,因此让我们删除对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块使用了它。如果String sql = ...不为空,则您尝试运行finally语句,然后关闭stmt

但是,INSERT从未分配stmt以外的任何值,因此仍为stmt。因此,null始终为null,因此stmt != null语句永远不会运行。您的false块永远不会执行任何操作,因此最好将其完全删除。随着INSERT块的消失,您还可以摆脱局部变量finallyfinally字符串,为我们留出一种方法,该方法的重点是截断表:

stmt

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


因此,总而言之,没有数据写入数据库,因为您从未调用过数据库以插入任何数据。在您的sql方法中,您正在创建参数源对象,但没有对其进行任何有用的操作;在您的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不为null,这行也不起作用,因为您没有在任何地方传递参数值:您会从数据库中获取异常,因为它将期望参数值,但您从未给出任何。

希望我的解释为您提供了一种使代码正常工作的方法,并且可以帮助您理解为什么没有这样做。

© www.soinside.com 2019 - 2024. All rights reserved.