ruby-on-rails - Rails 4. 唯一 ID 计数器

标签 ruby-on-rails ruby postgresql rails-activerecord uniqueidentifier

我需要为我的模型生成一个唯一编号,称为 Shipment。 该号码必须采用以下格式:

  • 两位数 - 当前月份
  • 两位数 - 当前年份
  • 六位数 - 只是数字

例如:1114000001。11 - 当前月份。 14 岁。 0000001 - 只有六位数。

所以。我的想法是使用 6 位数的计数器。我想将它存储在数据库中,然后我可以使用 lock 并确保唯一性。但很明显,这是一个潜在的瓶颈。因为每一个新的shipment都会排队等待访问counter

我的问题是:什么更好?使用计数器或生成一个随机数,并查询数据库:

while Shipment.where(:id => supposedly_unique_number.).exists?

还有一个问题:我该把计数器存放在哪里?整个申请我只需要一个。仅为一个值创建独立表?

更新

我刚刚意识到这张支票 Shipment.where(:id => supposedly_unique_number.).exists? 不保证唯一性。 :)

那么柜台存放在哪里比较好? 我很乐意听取您的任何建议。

更新 2

mu 太短,提到数据库序列。 而且我找不到如何使用它的可理解信息。 如果有人向我解释它是如何工作的,我将不胜感激。

Rails 4、Ruby 2、PostgreSql。

最佳答案

这里有几件事你需要考虑:

  1. 您的 id 将有前导零,因此它们不是数字,它们是包含数字字符的字符串。
  2. 您应该让数据库负责计数器。任何你试图在 Ruby 中做的事情都将是一团乱七八糟的困惑和竞争条件。同样,您应该让数据库负责构建 id

使用字符串作为 id 可以防止 ActiveRecord 认为它拥有您,但还不错。您需要创建没有create_table 添加的隐式id 的表,添加您自己的id,并手动将其设置为主键:

create_table :shipments, :id => false do |t|
  # Don't bother with `t.string` when using PostgreSQL, it is pointless.
  t.text :id, :null => false
  ...
end
connection.execute('alter table shipments add primary key (id)')

现在我们需要连接一个默认值,以便数据库可以生成我们的 id。获取日期前缀很简单,使用 to_char SQL function格式化当前时间(now()):

to_char(now(), 'MMYY')

要创建后缀,我们可以使用 sequence .数据库序列只是数据库对象,它在存在多个数据库连接的情况下以安全的方式返回递增的数字。首先,创建序列:

connection.execute('create sequence shipments_id_seq owned by shipments.id')

要从序列中获取下一个值,我们使用 nextval SQL function :

nextval(regclass)
Advance sequence and return new value

然后再次使用 to_char格式化它:

to_char(nextval('shipments_id_seq'), 'FM000000')

linked document解释了 FM000000 格式的含义。将 id 的这两部分组合起来,我们得到一个默认值:

to_char(now(), 'MMYY') || to_char(nextval('shipments_id_seq'), 'FM000000')

请注意,|| 是 SQL 中的字符串连接。将其包装在另一个 connection.execute 中让我们将默认值附加到 id 列:

connection.execute(%q{
  alter table shipments
  alter column id
  set default to_char(now(), 'MMYY') || to_char(nextval('shipments_id_seq'), 'FM000000')
})

如果您想在每个月的月初(或接近六位数限制时)重置计数器,您可以使用 setval SQL function .

最后,由于您正在使用 ActiveRecord 无法理解的各种东西,因此您需要从 schema.rb 切换到 structure.sql管理您的架构信息。您可以通过设置在配置中执行此操作:

config.active_record.schema_format = :sql

并且您将使用 rake db:structure:dumpdb:structure:load 而不是模式任务。


将所有这些放在一起将为您提供如下迁移:

def up
  create_table :shipments, :id => false do |t|
    # Don't bother with `t.string` when using PostgreSQL, it is pointless.
    t.text :id, :null => false
    ...
  end
  connection.execute('alter table shipments add primary key (id)')
  connection.execute('create sequence shipments_id_seq owned by shipments.id')
  connection.execute(%q{
    alter table shipments
    alter column id
    set default to_char(now(), 'MMYY') || to_char(nextval('shipments_id_seq'), 'FM000000')
  })
end

关于ruby-on-rails - Rails 4. 唯一 ID 计数器,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/26943277/

相关文章:

sql - pl/pgsql - 如何从另一个表创建一个表

postgresql - 如何从 plpgsql 中的多个表返回多行?

ruby - 不带参数调用 super

ruby - 如何将 DSL 元编程与 Sinatra 结合使用

regex - 如何匹配包含子字符串的模式

ruby-on-rails - PostgreSQL:postgres 不知道在哪里可以找到服务器配置文件。

postgresql - 将基于 postgis1.5 的转储导入 postgis2.0 数据库

ruby-on-rails - 将一长串文本粘贴到 Heroku rails 控制台中

ruby-on-rails - AWS RDS 扩展安装

ruby-on-rails - 为什么我的自引用模板会破坏控制台和 rake 中的缓存摘要计算,但不会破坏服务器中的缓存摘要计算?