如何简化此代码?

时间:2018-07-25 12:36:20

标签: java performance jdbc

此代码用于更新sql中的客户数据。如何简化此代码?还有另一种方法吗?

if (!clienteOld.getNome().equalsIgnoreCase(clienteNew.getNome())) {
        stmt.executeUpdate("UPDATE CLIENTES SET NOME = '" + clienteNew.getNome() + "' WHERE ID = " + id1 + ";");
        criarLog("Ficha do cliente: " + clienteOld.getNome() + " foi atualizada -- NOME=" + clienteNew.getNome());
    }
    if (!clienteOld.getDataNascimento().equalsIgnoreCase(clienteNew.getDataNascimento())) {
        stmt.executeUpdate("UPDATE CLIENTES SET DATA_NASCI = '" + clienteNew.getDataNascimento() + "' WHERE ID = " + id1 + ";");
        criarLog("Ficha do cliente: " + clienteOld.getNome() + " foi atualizada -- DATA NASCIMENTO=" + clienteNew.getDataNascimento());
    }
    if (!clienteOld.getMorada().equalsIgnoreCase(clienteNew.getMorada())) {
        stmt.executeUpdate("UPDATE CLIENTES SET MORADA = '" + clienteNew.getMorada() + "' WHERE ID = " + id1 + ";");
        criarLog("Ficha do cliente: " + clienteOld.getNome() + " foi atualizada -- MORADA=" + clienteNew.getMorada());
    }
    if (!clienteOld.getPais().equalsIgnoreCase(clienteNew.getPais())) {
        stmt.executeUpdate("UPDATE CLIENTES SET PAIS = '" + clienteNew.getPais() + "' WHERE ID = " + id1 + ";");
        criarLog("Ficha do cliente: " + clienteOld.getNome() + " foi atualizada -- PAIS=" + clienteNew.getPais());
    }
    if (!clienteOld.getNacionalidade().equalsIgnoreCase(clienteNew.getNacionalidade())) {
        stmt.executeUpdate("UPDATE CLIENTES SET NACIONALIDADE = '" + clienteNew.getNacionalidade() + "' WHERE ID = " + id1 + ";");
        criarLog("Ficha do cliente: " + clienteOld.getNome() + " foi atualizada -- NACIONALIDADE=" + clienteNew.getNacionalidade());
    }
    if (!clienteOld.getBI().equalsIgnoreCase(clienteNew.getBI())) {
        stmt.executeUpdate("UPDATE CLIENTES SET BI = '" + clienteNew.getBI() + "' WHERE ID = " + id1 + ";");
        criarLog("Ficha do cliente: " + clienteOld.getNome() + " foi atualizada -- BI=" + clienteNew.getBI());
    }
    if (!clienteOld.getTipoIndentificaçao().equalsIgnoreCase(clienteNew.getTipoIndentificaçao())) {
        stmt.executeUpdate("UPDATE CLIENTES SET TIPO_IDENT = '" + clienteNew.getTipoIndentificaçao() + "' WHERE ID = " + id1 + ";");
        criarLog("Ficha do cliente: " + clienteOld.getNome() + " foi atualizada -- TIPO IDENTIFICAÇAO=" + clienteNew.getTipoIndentificaçao());
    }

3 个答案:

答案 0 :(得分:1)

尝试以下逻辑:

StringBuilder sql = new StringBuilder("UPDATE CLIENTES SET ");
Map<String, String> cols = new HashMap<>();

if (!clienteOld.getNome().equalsIgnoreCase(clienteNew.getNome())) {
    cols.put("NOME", clienteNew.getNome());
}
if (!clienteOld.getDataNascimento().equalsIgnoreCase(clienteNew.getDataNascimento())) {
    cols.put("DATA_NASCI", clienteNew.getDataNascimento());
}
// and the other if statements

然后,您可以迭代地图并构建实际的更新语句:

int cnt = 0;
for (Map.Entry<Integer, Integer> entry : cols.entrySet()) {
    if (cnt > 0) sql.append(", ");
    sql.append(entry.getKey()).append(" = '").append(entry.getValue()).append("'");
    ++cnt;
}

sql.append(" WHERE ID = ").append(id1).append(";");

但是请注意,这种方法不是SQL注入安全的 。如果这些值来自外部,例如UI,那么您绝对应该使用准备好的语句。对每个if条件使用单独的语句本质上没有错。我只是回答表明,如果合适,您可以清理当前的方法。

答案 1 :(得分:1)

    if (!oldClient.getName().equalsIgnoreCase(newClient.getName())) {
        stmt.executeUpdate("UPDATE CLIENTS SET NAME = '" + newClient.getName() +
                           "' WHERE ID = " + id1 + ";");
    }
    if (!oldClient.getBirthDate().equalsIgnoreCase(newClient.getBirthDate())) {
        stmt.executeUpdate("UPDATE CLIENTS SET BIRTH = '" + newClient.getBirthDate() +
                           "' WHERE ID = " + id1 + ";");
    }

可以改写为

    if (!oldClient.getName().equalsIgnoreCase(newClient.getName()) ||
        !oldClient.getBirthDate().equalsIgnoreCase(newClient.getBirthDate())) {
        stmt.executeUpdate("UPDATE CLIENTS SET NAME = '" + newClient.getName() +
                           "', BIRTH = '" + newClient.getBirthDate() +
                           "' WHERE ID = " + id1 + ";");
    }

这将更好地执行,因为它执行一个SQL语句而不是两个。与之相比,当您只需要设置一列时就可以设置两列的事实可能没有多大意义。

注意:

  1. 如果尝试“优化”设置的列数,则代码会更加复杂;参见蒂姆的答案。

  2. 这可能应该使用PreparedStatement和语句参数来完成,以避免SQL注入。如果遵循上述模式,则直接使用PreparedStatement所需的更改。

答案 2 :(得分:0)

首先,您可以使用一个查询来更新每个字段:

"UPDATE CLIENTES SET DATA_NASCI "
    + "MORADA = '" + clienteNew.getMorada() + "'"
    + "PAIS = '" + clienteNew.getPais() + "'"
    + "NACIONALIDADE = '" + clienteNew.getNacionalidade() + "'"
    + "BI = '" + clienteNew.getBI() + "'"
    + "TIPO_IDENT = '" + clienteNew.getTipoIndentificaçao() + "'"
    + "WHERE ID = " + id1 + ";"

请使用PreparedStatement代替它,这样会更安全!

您要做的就是使用条件检查是否只有一个字段发生了更改(以防止事务不执行任何操作):

if (!clienteOld.getNome().equalsIgnoreCase(clienteNew.getNome()))
      || (clienteOld.getDataNascimento().equalsIgnoreCase(clienteNew.getDataNascimento())) 
    || (!clienteOld.getMorada().equalsIgnoreCase(clienteNew.getMorada()))
    || (!clienteOld.getPais().equalsIgnoreCase(clienteNew.getPais()))
    || (!clienteOld.getNacionalidade().equalsIgnoreCase(clienteNew.getNacionalidade())) 
    || (!clienteOld.getBI().equalsIgnoreCase(clienteNew.getBI())) 
    || (!clienteOld.getTipoIndentificaçao().equalsIgnoreCase(clienteNew.getTipoIndentificaçao()))

这可能有点冗长...所以为什么不使用Stream和一些函数引用来比较并构建要更新的值映射呢?

首先,我们的示例为Bean类:

class Bean {
    String firstname, lastname;

    public Bean(String firstname, String lastname) {
        this.firstname = firstname;
        this.lastname = lastname;
    }

    public String getFirstname() {
        return firstname;
    }

    public String getLastname() {
        return lastname;
    }
}

然后,我们创建一个Column nameFunction的映射,该函数将允许我们使用Bean的吸气剂:

Map<String, Function<Bean, String>> functions = new HashMap<>();
functions.put("FIRSTNAME", Bean::getFirstname);
functions.put("LASTNAME", Bean::getLastname);

然后,使用final实例(在谓词中使用)

final Bean clienteNew = new Bean("Foo", "Bar");
final Bean clienteOld = new Bean("Foo", "Boo");


Map<String, String> values = functions.entrySet()
    .stream()
    //filter only the value that changed between clienteOld and clienteNew
    .filter(entry -> !entry.getValue().apply(clienteOld).equals(entry.getValue().apply(clienteNew)))
    //then collect the map `name -> new value`
    .collect(Collectors.toMap(e -> e.getKey(), e -> e.getValue().apply(clienteNew)));

System.out.println(values);
  

{LASTNAME = Bar}

这将为您提供一个Map<String, String>,可用于仅创建我们想要/需要编辑的列即可创建PreparedStatement

如果您有一个新字段,只需将映射添加到functions映射中就可以了。 (使用原始类型会变得更加复杂...)