如何在不发出额外查询的情况下更新刚刚检索到的记录?

Posted

技术标签:

【中文标题】如何在不发出额外查询的情况下更新刚刚检索到的记录?【英文标题】:How do I update just retrieved records without issuing an additional query? 【发布时间】:2013-04-06 08:35:16 【问题描述】:

我有以下代码:

String sql = "SELECT * FROM users WHERE email = " + email;
prestat = DBConnection.prepareStatement(sql);
rs = prestat.executeQuery();
boolean isEmpty = !rs.first();
if (isEmpty) 
  // Special marker for nonexistent user
  return "$null";
 else if (password.equals(rs.getString(2))) 
  String uuid = UUID.randomUUID().toString();
  // Here I want to insert the UUID into the database
   

考虑到我已经搜索过数据库,我想知道是否有一种方法可以获取行号/位置,并使用它来更新 UUID 列,从而防止再次搜索数据库。

【问题讨论】:

我正在使用 Apache Derby。 【参考方案1】:

目前尚不清楚您要在这里做什么,而且您似乎并不真正了解发生了什么。例如,当使用准备好的语句时,不会使用两个连接的字符串来提供它,而是这样做:

PreparedStatement stmt =
        conn.prepareStatement("SELECT * FROM foo WHERE bar = ?");
stmt.setString(1, "Hello World!");

那么,如果你真的想避免双重搜索,你可以简单地假设一个乐观的观点:

UPDATE users SET uuid = ? WHERE email = ? AND password = ?

顺便说一句,确保电子邮件是唯一的。另外,也许您已经这样做了,但不要在数据库中保存明文密码。改用加密哈希,然后加盐。

由于您指定您的后端是 Apache Derby,也许this guide 可以帮助您解决问题(它是 100% Java 但不是真正可移植的,因为不同的后端可能无法实现所有必需的功能)。基本上,您在准备语句时传递了两个标志:

Statement stmt = con.createStatement(
    ResultSet.TYPE_FORWARD_ONLY, 
    ResultSet.CONCUR_UPDATABLE);
ResultSet res = stmt.executeQuery("SELECT * FROM users WHERE email = ?");

然后你有一个由可更新游标支持的ResultSet,所以你可以调用:

res.updateString("uuid", uuid);
res.updateRow();

我认为这可能可以避免额外的搜索,但是我没有对其进行测试,也不能说是否有真正的性能提升。不过,这听起来像是过早的优化。

【讨论】:

我才刚刚开始开发。将很快添加散列。而关于stmt.setString(),有什么性能差异吗?关于双重搜索,我不明白更新将如何阻止第二次搜索。我的问题是,鉴于我已经进行了第一次搜索,我该如何避免第二次搜索。由于其他原因,我需要第一次搜索。 第一次搜索时不要使用SELECT。只有UPDATE,因为WHERE 子句中的条件是您的两个if 块的SQL 等价物。 根据实现的不同,可能会有性能优势,但准备好的语句的主要用途是增强您的应用程序以防止格式错误(或恶意)输入 如果我这样做,我如何区分电子邮件错误和密码错误?如果用户根本不存在怎么办? 如果没有更大的上下文,我不能说这是否相关,或者您是否可以通过简单地说明电子邮件密码不匹配来确定【参考方案2】:

你可以简单地替换

prestat = DBConnection.prepareStatement("SELECT * FROM users WHERE email =" + email);

通过

prestat = DBConnection.prepareStatement("Update users set uuid = '" + uuid + "' WHERE email =" + email);

当然还有执行。

【讨论】:

啊。对不起。我的错。我应该删除该声明。我知道这是错的。这就是我发表评论的原因。

以上是关于如何在不发出额外查询的情况下更新刚刚检索到的记录?的主要内容,如果未能解决你的问题,请参考以下文章

如何在不使用 GROUP BY 子句的情况下获取列值

如何在不停机的情况下更新和 ECS 服务添加一个额外的负载平衡服务与之对话?

Django ORM:在不执行 N+1 查询的情况下检索帖子和最新评论

如何在不打开的情况下从 CSV 文件中检索数据

如何在不参考 BigQuery 中的父记录的情况下查询嵌套记录中的字段?

在 FaunaDB 中更新记录时,如何在不传入每个字段和子对象的情况下更新一个字段?