使用 JDBC 更新数据库,其中包含一些应忽略的值

Posted

技术标签:

【中文标题】使用 JDBC 更新数据库,其中包含一些应忽略的值【英文标题】:Update Database with JDBC having some values which should be ignored 【发布时间】:2020-03-15 23:27:27 【问题描述】:

我在使用 JDBC 更新表列时遇到了一些麻烦。如果我有一张表格,例如 User(name,address,hobby,...) 想象一下大约 15 个字段。然后我通过前端从表单中获取一个对象,用户可以在其中输入所有应该更改的条目。现在我需要将更改保存在数据库中,但并非所有字段都已更改,因此我的 DAO 有一些 null 值。例如 nameaddress 应该更改,表中的其他条目不应该更改。有什么聪明的方法可以把它放到 JDBC PreparedStatement 中吗?或者您知道其他解决方案吗?我试图避免大量的value != null 声明。

提前致谢!

(我使用 spring 作为后端,并且在前端使用 angular)

【问题讨论】:

没有任何代码很难帮助你。在我的脑海中,您应该首先从数据库中检索实际值,然后让用户修改这些值。那么你就不会有任何空值了。 【参考方案1】:

由于您使用的是 Spring,您可以使用 NamedParameterJdbcTemplate,但真正的技巧是使用 COALESCE 在给定值为 NULL 时使用备用值:

@Autowired
private DataSource dataSource;

public void updateUser(int id, String name, String address, String hobby) 
    NamedParameterJdbcTemplate jdbcTemplate = new NamedParameterJdbcTemplate(dataSource);
    String sql = "UPDATE User" +
                   " SET Name = COALESCE(:name, Name)" +
                      ", Address = COALESCE(:address, Address)" +
                      ", Hobby = COALESCE(:hobby, Hobby)" +
                 " WHERE Id = :id";
    MapSqlParameterSource paramMap = new MapSqlParameterSource();
    paramMap.addValue("id"     , id     , Types.INTEGER);
    paramMap.addValue("name"   , name   , Types.VARCHAR);
    paramMap.addValue("address", address, Types.VARCHAR);
    paramMap.addValue("hobby"  , hobby  , Types.VARCHAR);
    if (jdbcTemplate.update(sql, paramMap) == 0)
        throw new EmptyResultDataAccessException("User not found: " + id, 1);

或者,如果您对用户数据使用 POJO:

public class User 
    private int id;
    private String name;
    private String address;
    private String hobby;

    // Getters and setters here

public void updateUser(User user) 
    NamedParameterJdbcTemplate jdbcTemplate = new NamedParameterJdbcTemplate(dataSource);
    String sql = "UPDATE User" +
                   " SET Name = COALESCE(:name, Name)" +
                      ", Address = COALESCE(:address, Address)" +
                      ", Hobby = COALESCE(:hobby, Hobby)" +
                 " WHERE Id = :id";
    BeanPropertySqlParameterSource paramMap = new BeanPropertySqlParameterSource(user);
    if (jdbcTemplate.update(sql, paramMap) == 0)
        throw new EmptyResultDataAccessException("User not found: " + id, 1);

【讨论】:

【参考方案2】:

您可以使用的简单解决方案是使用 SimpleJdbcInsert 并添加 usingGeneratedKeyColumns("ID")。

@Autowired
private DataSource dataSource;
    
@Override
    public ResponseEntity<Void> insertEntity(Entity obj) 
        SimpleJdbcInsert simpleJdbcInsert = new SimpleJdbcInsert(jdbcTemplate.getDataSource());
        simpleJdbcInsert.withTableName(TABLE_APP_REPO).usingGeneratedKeyColumns("ID");
        BeanPropertySqlParameterSource paramSource = new BeanPropertySqlParameterSource(obj);

        try 
            simpleJdbcInsert.execute(paramSource);
         catch (Exception e) 
            return ResponseEntity.badRequest().build();
        
        return ResponseEntity.ok().build();
    

【讨论】:

以上是关于使用 JDBC 更新数据库,其中包含一些应忽略的值的主要内容,如果未能解决你的问题,请参考以下文章

更新 CoreData 中的数据及其在视图中的值

MySqlDb 在插入忽略语句中抛出操作数应包含 1 列

插入、替换/更新 JDBC

用另一个表上的值更新新添加的列

响应式网格忽略了空 div?

为啥 EF 核心忽略我对数据集的更新?