我正在尝试解析管道分隔文件并将字段插入表中。当我启动应用程序时,数据库中什么也没有发生。我的数据库有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 +"]";
}
}
[看一下您提供的内容,似乎您杂乱无章地收集了一些代码,虽然其中大部分都在那里,但并不是全部都存在,也不是全部都以正确的顺序排列。
为了获得某种程度的清晰度,请尝试将您要执行的操作分解为单独的步骤,并有一种方法专注于每个步骤。特别是你写
我正在尝试解析管道分隔文件并将字段插入表中
这自然分为两部分:
对于第一部分,您似乎已经在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
块的消失,您还可以摆脱局部变量finally
和finally
字符串,为我们留出一种方法,该方法的重点是截断表:
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,这行也不起作用,因为您没有在任何地方传递参数值:您会从数据库中获取异常,因为它将期望参数值,但您从未给出任何。
希望我的解释为您提供了一种使代码正常工作的方法,并且可以帮助您理解为什么没有这样做。