Heroku PostgreSQL:重启添加重复行

Posted

技术标签:

【中文标题】Heroku PostgreSQL:重启添加重复行【英文标题】:Heroku PostgreSQL: Restart adds duplicate lines 【发布时间】:2020-02-23 01:16:22 【问题描述】:

我有一个使用 PostgreSQL 插件在 Heroku 上运行的 Spring Boot 应用程序。在启动时,spring boot 会自动在 PostgreSQL 中创建一些虚拟数据,例如 users 及其联系信息。表和insert语句存储在Schema.sql(pastebin)和Data.sql(pastebin)中

第一次启动时一切正常,但在我重新启动后,spring boot 应用程序再次创建相同的行,这会导致出现重复行、重复关系等错误。

如何在重启时禁用数据娱乐?

Heroku Config Vars 设置为:

每个 SQL 插入语句都有 ON CONFLICT DO NOTHING,每个创建表语句都有 IF NOT EXISTS

【问题讨论】:

“在启动时 spring boot 会自动创建一些虚拟数据”——你为什么在你的应用程序启动时这样做? @Chris 因为我希望在启动时存在一些数据。当应用程序在使用时,它基本上可以让人们看到一切看起来如何。 对,但为什么应用程序启动?将其作为部署的一部分,或者更好的是,通过运行脚本明确地播种它不是更有意义吗?这听起来像是一次性任务,而不是每天都应该发生的事情(Heroku dynos 经常重启)。或者,根据数据,它可能属于数据库迁移。 @Chris 我希望应用程序启动时数据始终相同。这样,当参与者在那里添加他们自己的东西时,它会在 Dyno 重新启动时的某个时间点被删除。重点是显示“起始”数据,并且每次重新启动后起始数据都应该始终存在。即使用户决定搞砸它。 【参考方案1】:

虽然@richyen 已正确识别问题,但我会建议一个不同的解决方案:修复您的架构并为您的用户使用natural keys,而不是(或至少除了)surrogate serial key。

CREATE TABLE IF NOT EXISTS users(
  id SERIAL PRIMARY KEY,
  username varchar(255) UNIQUE NOT NULL,
--                      ^^^^^^
  email varchar(255) UNIQUE NOT NULL,
--                   ^^^^^^
  PASSWORD varchar(255) NOT NULL,
  enabled INTEGER DEFAULT 0,
  created_at TIMESTAMP,
  modified_at TIMESTAMP,
  removed_at TIMESTAMP
);

(A PRIMARY KEYUNIQUE NOT NULL 完全相同,只是你只能拥有它一次,并且它成为对未显式指定列的表的外键引用的默认值).

当您尝试插入具有相同姓名或电子邮件地址的用户时,这将导致预期的冲突。

【讨论】:

我按照你@Bergi 所说的做了,它就像richyen 所说的那样工作。我对这两个答案都投了赞成票,并选择了这个作为答案,因为它解决了我的问题。 这是一个很好的观点——对“重要的事情”的独特限制。我一定会把它添加到我的建议清单中:D【参考方案2】:

这里的问题是,即使您指定了ON CONFLICT DO NOTHING,您也没有在您的INSERT 语句中指定id 列。这不一定是坏事,但基本上它会使您的 ON CONFLICT DO NOTHING 子句无效(至少为了启动顺序)。您将永远不会遇到冲突,因为id 列是一个序列并且它是您的主键。因此,如果您没有在INSERT 语句中明确命名它,数据库将很高兴地添加另一行,该行具有该id 序列的“下一个”值,以及在您的INSERT 中命名的其他列。只有当您遇到主键有两个相同值的情况时才会发生冲突,而在您的 Data.sql 中,您永远不会遇到这种情况。

如果您真的想要ON CONFLICT DO NOTHING 行为,那么您需要在您的INSERTs 中添加一个id 列,然后确保将您的序列设置为setval(),以便您生成的新行应用程序不会因为id 冲突而无意中删除/忽略。

另一个选项(如果您的数据集仅用于开发)是截断您的表,以便您每次都能获得干净的工作数据集(但这取决于您的要求)。如果您这样做,那么您还需要重置您的序列,这样您的ids 就不会永远保持增长。

最后,既然您已经加载了种子数据,您就可以设置SPRING_DATASOURCE_INITIALIZATION_MODE = Never。同样,这只是您需要根据您的要求做出的决定。

【讨论】:

以上是关于Heroku PostgreSQL:重启添加重复行的主要内容,如果未能解决你的问题,请参考以下文章

Heroku 和 Django 组合中的 Postgresql 更改与共享数据库

Heroku上的现有Ruby on Rails Web应用程序(PostgreSQL),Devise身份验证,需要为移动支持添加Rails API

如何设置 heroku postgresql 应用程序的路径?

Heroku 为啥使用 Postgresql?

PostgreSQL:如何连接行[重复]

为 Heroku 重写 PostgreSQL 查询