4

我有一个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在这种情况下我不能抛出 a)?
  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.");  
    }
4

7 回答 7

2

I'd go with option 3 for the reusability and sanity aspect, unless you're worried about a couple of extra queries for (very strict and not obvious) performance reasons.

Since you'll likely reuse the code to retrieve the user in other places, I'd first retrieve the user, and return a 404 if he's not found. Then I'd call update and sanity check the number of rows changed. Finally, I'd call the retrieval method to get the user and marshall it into the response body. It's simple, it works, it's readable, it's predictable, it's testable, and it's most likely fast enough. And you've just reused your retrieval method.

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

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

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

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

于 2013-07-16T11:45:16.467 回答
2

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

于 2013-07-23T00:36:10.857 回答
1

在达成解决方案之前,需要考虑的事项很少。

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

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

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

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

于 2013-07-23T08:59:58.350 回答
1

我有一个类似的问题。这是我解决这个问题的方法

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

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

不确定这是否是正确的方法,但这有效。有人可以告诉一个更好或更正确的方法。

于 2013-07-13T15:34:00.120 回答
1

我认为最安全的方法是:

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

这将返回 id=3 的行数。然后你可以返回它并检查 columnCount 是否为 1,然后执行 update 语句,否则执行其他操作。

于 2013-07-20T11:04:57.197 回答
0

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

于 2013-07-23T06:51:38.390 回答