【问题标题】:How to validate if a record exists when issuing a REST update request using spring jdbcTemplate?使用spring jdbcTemplate发出REST更新请求时如何验证记录是否存在?
【发布时间】:2013-07-13 15:20:36
【问题描述】:

我有一个简单的数据库表 users,有 3 列:

| id | username | nationality | 
|  1 |   John   | American    | 
|  2 |   Doe    | English     |

我想通过POST 请求向http://mysite/users/2/nationality 发布更新

现在我最初的方法是做一个查询

UPDATE users SET nationality="French" WHERE id=2; 后跟更新对象SELECT * FROM users WHERE id=2; 的查询,然后在响应中返回更新后的对象。

问题是我的数据库中可能不存在请求中传递的id我应该如何验证用户是否存在于数据库中?

  1. 我应该只检查查询是否返回对象吗?
  2. 我是否应该首先验证受影响行的更新(受影响的 如果未对要存储的数据进行任何更改,则行将为零 更新了,所以在这种情况下我不能抛出UserNotFoundException)?
  3. 在更新之前发出查询以检查是否更好 行存在然后更新然后查询更新的行?
  public void updateRecord(Long id, String username) {  
 String updateSql = "UPDATE users SET username = ? WHERE id = ?";  
 JdbcTemplate template = new JdbcTemplate(dataSource);  
   Object[] params = { username, id};  
    int[] types = {Types.VARCHAR, Types.BIGINT};  
    int rows = template.update(updateSql, params, types);  
    System.out.println(rows + " row(s) updated.");  
    }

【问题讨论】:

    标签: java mysql spring rest jdbctemplate


    【解决方案1】:
    1. 如果您总是需要更新以在响应中返回更新后的对象,那么选项 1 似乎是检查更新是否与现有用户匹配的合理方法。虽然如果您不使用事务,您应该知道用户在更新时可能不存在,但单独的连接可以在您的选择之前插入用户。

      也就是说,在没有事务的情况下,选择总是有可能以与您刚刚执行的更新不同的状态返回对象。不过,在这种情况下情况会稍差一些,因为从技术上讲,更新应该失败了。

    2. 如果您不需要更新以在响应中返回更新后的对象,那么选项 2 似乎是一个更好的解决方案。但是,要使其正常工作,您需要更新以返回匹配的行数而不是更改的行数(因此,如果更新与现有用户匹配,但您正在更新的字段没有更改,您仍然会得到一个非零的结果)。

      通常您必须设置一个连接属性才能使此功能适用于 MySQL(例如,在 PHP 的 PDO 驱动程序中有 MYSQL_ATTR_FOUND_ROWS 属性)。但是,我的理解是这个选项是already enabled in JDBC 所以executeUpdate 应该返回匹配的行数。目前我无法确认,但它应该很容易让您测试。

    【讨论】:

      【解决方案2】:

      在您的情况下,最好的方法是针对给定的 id 运行选择查询,以验证数据库中是否存在相应的记录。如果记录存在,那么您可以继续成功流程并运行您上面提到的更新和选择查询。否则,如果记录不存在,那么您可以继续失败流程(抛出异常等)

      【讨论】:

        【解决方案3】:

        出于可重用性和完整性方面的考虑,我会选择选项 3,除非您出于(非常严格且不明显的)性能原因而担心一些额外的查询。

        由于您可能会在其他地方重用代码来检索用户,所以我会先检索用户,如果找不到他,则返回 404。然后我会调用更新和健全性检查更改的行数。最后,我会调用检索方法来获取用户并将其编组到响应正文中。它简单、有效、可读、可预测、可测试,而且很可能足够快。而且您刚刚重用了您的检索方法。

        【讨论】:

          【解决方案4】:

          我遇到了类似的问题。这是我解决问题的方法

          1. 每当它是新用户时,用默认数字(例如 51002122)标记 id 此处 51002122 绝不是 db 中的 id。所以页面显示“/51002122/user”。当用户的 id 是 51002122 时,我会插入 db。插入后,我使用 db 中的 id 呈现页面。例如。插入后,页面将是“/27/user”。

          2. 对于除 51002122 以外的所有其他 ID(例如 /12/user 或 /129/user ),我会在数据库中进行更新,因为我知道该用户存在于数据库中。

          不确定这是否是正确的方法,但可行。有人能说出更好或更正确的方法吗?

          【讨论】:

            【解决方案5】:

            我认为最安全的方法是:

            SELECT EXISTS(
                         SELECT *
                         FROM users
                         WHERE id =  3 ) as columnCount;
            

            这将返回 id=3 的行数。然后你可以返回 this 并检查 columnCount 是否为 1,然后执行 update 语句 else 做其他事情。

            【讨论】:

              【解决方案6】:

              在找到解决方案之前,需要考虑几件事。

              1. 这是一个 REST API 调用,从使用的角度要求简单
              2. 服务器端代码还应考虑所选实现的性能含义。
              3. API 应该健壮。意思是,无论如何,请求应该始终采用设计中设想的流程(快乐/异常)。

              基于这些考虑,我建议采用以下方法。

              1. 在DAO中,定义两个不同的方法,分别是updateRecord(Long id, String username)getRecord(Long id)
              2. 将事务属性(@Transaction)标记到这些方法如下
                • updateRecord 的事务属性标记为REQUIRED
                • getRecord 的事务属性标记为NOT_REQUIRED,因为这纯粹是一个读取调用。
              3. 请注意,在所有情况下,至少需要进行 DB 调用。
              4. 从控制器,首先调用updateRecord 方法。此方法将返回一个整数。
              5. 如果返回值非零,则调用getRecord 从数据库中检索更新的记录。
              6. 如果返回值为零,则表示用户不存在,无需调用getRecord。对返回给调用客户端的适当错误响应 (404 Not Found )。
              7. 在这种方法中,您将在用户不存在时保存一次数据库调用。

              总体而言,这种方法很简洁,不那么混乱,最重要的是简单高效(我们将事务边界限制为仅用于更新调用)。此外,getRecord 可以独立用作另一个 API 来检索记录(无需事务)。

              【讨论】:

                【解决方案7】:

                我有类似的问题,我应该更新一个表,但在此之前需要检查 id 是否存在。我使用了 openjpa 并编写了方法 verifyUser(id) ,其中 id 是我需要检查的。 OpenJpa findById 将记录返回给您。在更新时它会返回完整的记录,而在添加时它会返回新的主键,通过该主键添加记录。我不确定它是如何用于休眠的,但是 jpa n hibernate 有很多相似之处。

                【讨论】:

                  猜你喜欢
                  • 1970-01-01
                  • 1970-01-01
                  • 1970-01-01
                  • 2021-03-15
                  • 2023-03-22
                  • 2019-05-21
                  • 1970-01-01
                  • 2017-09-09
                  • 1970-01-01
                  相关资源
                  最近更新 更多