如何在 Sequel 数据集上更新或插入?

Posted

技术标签:

【中文标题】如何在 Sequel 数据集上更新或插入?【英文标题】:How to update or insert on Sequel dataset? 【发布时间】:2012-03-19 11:06:29 【问题描述】:

我刚开始在一个非常小的 Sinatra 应用程序中使用 Sequel。由于我只有一个 DB 表,因此我不需要使用模型。

我想更新一条记录(如果存在)或插入一条新记录(如果不存在)。我想出了以下解决方案:

  rec = $nums.where(:number => n, :type => t)
  if $nums.select(1).where(rec.exists)
    rec.update(:counter => :counter + 1)
  else
    $nums.insert(:number => n, :counter => 1, :type => t)
  end

其中$numsDB[:numbers] 数据集。

我相信这种方式并不是“更新或插入”行为的最优雅的实现方式。

应该怎么做?

【问题讨论】:

***.com/questions/3647454/… 【参考方案1】:

您可能不应该在更新/插入之前检查;因为:

    这是一个额外的数据库调用。 这可能会引入竞争条件。

你应该做的是测试更新的返回值:

rec = $nums.where(:number => n, :type => t)
if 1 != rec.update(:counter => :counter + 1)
  $nums.insert(:number => n, :counter => 1, :type => t)
end

【讨论】:

这是一个不错的解决方案。谢谢 这个解决方案仍然引入了竞态条件的可能性。如果两个并行进程/线程在其中一个到达插入(第 3 行)之前执行更新(第 2 行),则将插入两条记录。考虑使用互斥锁、数据库锁或适当的事务策略。 Flexoid:你是对的,下面的解决方案 - 基本上“将所有内容放入事务中”是正确的。尽管如此,当“UPDATE + INSERT”足够时,“SELECT、UPDATE、INSERT”命令的顺序是没有意义的。 (当然是事务。)事务的有趣之处:如果两个并行运行的事务递增相同的计数器,您仍然会遇到问题。【参考方案2】:

续集 4.25.0(2015 年 7 月 31 日发布)添加了 insert_conflict for Postgres v9.5+ 续集 4.30.0(2016 年 1 月 4 日发布)添加 insert_conflict for SQLite

这可用于插入或更新一行,如下所示:

DB[:table_name].insert_conflict(:update).insert( number:n, type:t, counter:c )

【讨论】:

【参考方案3】:

我相信你不能让它比这更干净(尽管有些数据库有特定的 upsert 语法,可能是supported by Sequel)。你可以把你拥有的东西包装在一个单独的方法中,并假装它不存在。 :)

只是几个建议:

将所有内容包含在事务中。 在(number, type) 字段上创建唯一索引。 不要使用全局变量。

【讨论】:

【参考方案4】:

您可以使用upsert,但它目前不适用于更新计数器。希望未来的版本能够 - 欢迎提出想法!

【讨论】:

以上是关于如何在 Sequel 数据集上更新或插入?的主要内容,如果未能解决你的问题,请参考以下文章

如何在大型数据集上执行克里金(高斯过程回归)?

什么是维度诅咒?如何评估降维算法在当前任务数据集上的效果?

我如何识别数据集上的可变目标以进行机器学习预测

30分钟掌握沧湖一体化:flink+hudi(干货,建议收藏)

如何评估不同模型在一个数据集上的性能?

当没有为它们提供注释时,如何在 PascalVOC 2012 或 COCO 测试集上测试模型?