如何使用spring jdbcTemplate在发出REST更新请求时验证是否存在记录?

时间:2013-07-13 15:20:37

标签: java mysql spring rest jdbctemplate

我有一个简单的数据库表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. 最好在更新之前发出查询,以检查是否更新 行存在然后更新然后查询更新的行?
  4.   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.");  
        }
    

7 个答案:

答案 0 :(得分:2)

  1. 如果您始终需要更新以在响应中返回更新的对象,则选项1似乎是检查更新是否与现有用户匹配的合理方法。虽然如果您没有使用交易,但您应该知道在更新时用户可能不存在,但是单独的连接可能会在您选择之前插入用户。

    也就是说,没有事务,select总是有可能将对象返回到与刚执行的更新不同的状态。但是,在这种情况下,情况稍差,因为从技术上讲,更新应该失败。

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

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

答案 1 :(得分:2)

我选择使用选项3来获得可重用性和理智性方面,除非您担心(非常严格且不明显)性能原因引起的一些额外查询。

由于您可能会重复使用该代码来检索其他地方的用户,因此我首先检索该用户,如果找不到,则返回404。然后我调用update和sanity检查更改的行数。最后,我调用检索方法来获取用户并将其编组到响应主体中。它很简单,有效,可读,可预测,可测试,而且最有可能足够快。而且您只是重复使用了检索方法。

答案 2 :(得分:2)

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

答案 3 :(得分:1)

我有类似的问题。以下是我解决问题的方法

  1. 每当它是一个新用户,然后用默认号码标记id(例如51002122),这里51002122永远不是db中的id。所以页面显示“/ 51002122 / user”。当用户的id是51002122然后我会插入db。在插入之后,我使用db的id渲染页面。例如。插入后,页面将是“/ 27 / user”。

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

    < / LI>

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

答案 4 :(得分:1)

我认为最安全的方式是:

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

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

答案 5 :(得分:1)

在得出解决方案之前,很少有事情需要考虑。

  1. 这是一个REST API调用,从使用角度来看需要简单
  2. 服务器端代码还应考虑所选实施的性能含义。
  3. API应健壮。意思是,请问应该总是采用设计中设想的流程(快乐/例外)。
  4. 基于这些考虑,我建议采用以下方法。

    1. 在DAO中,定义两种不同的方法,即updateRecord(Long id, String username)getRecord(Long id)
    2. 将事务属性(@Transaction)标记为这些方法,如下所示
      • updateRecord的交易属性标记为REQUIRED
      • getRecord的交易属性标记为NOT_REQUIRED,因为这只是一个读取调用。
    3. 请注意,在所有情况下,至少需要进行数据库调用。
    4. 从控制器,首先调用updateRecord方法。此方法将返回一个整数。
    5. 如果返回的值非零,则调用getRecord以从数据库中检索更新的记录。
    6. 如果返回值为零,则表示用户不存在,无需调用getRecord。返回给调用客户端的相应错误响应(404 Not Found)。
    7. 在此方法中,当用户不存在时,您将保存一个数据库调用。
    8. 总的来说,这种方法很简洁,不那么杂乱,最重要的是简单而有效(我们只限制更新调用的事务边界)。此外,getRecord可以独立用作另一个API来检索记录(无事务)。

答案 6 :(得分:0)

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