处理并发任务
Handling concurrent tasks
我有多个并发任务,它们都试图检查记录是否存在,如果不存在,将插入一个。
不幸的是,我最终将记录重复写入数据库,因为似乎所有任务都决定同时不存在该记录,然后所有任务都进行插入。
期望的行为是我只得到一次插入,然后其他任务就会识别出刚刚插入的记录的存在。
这是我的尝试:
alias MyApp.Parent, as: Parent
alias MyApp.Repo, as: Repo
changeset = Parent.changeset(%Parent{}, model)
case Repo.all(from p in Parent, where: p.mobile_number == ^model.mobile_number) do
[] ->
#does not exist
case Repo.insert_or_update(changeset) do
{:ok, %MyApp.Parent{ id: parent_id }} -> parent_id
error_message -> nil
end
[parent_get_by|t] ->
#already exist
%MyApp.Parent{ id: parent_id }= parent_get_by
parent_id
end
感谢任何帮助!
您应该在数据库中为 mobile_number
字段添加一个 UNIQUE INDEX
。它会更有效率(您只需要对数据库执行一个查询)并且您可以保证数据库永远不会在 table.
中的该字段具有重复值
您需要做三件事:
使用迁移将 unique_index
添加到 table。
在您的变更集函数中添加对 unique_constraint
的调用。
在您的控制器中,只需执行 Repo.insert(changeset)
。如果该字段重复,您将得到 {:error, changeset}
返回并在 changeset.errors
.
中显示错误消息
接受的答案很好。
但是当您不能强制执行唯一索引时,您有两种选择。首先是使用锁,以防止进程同时查询数据库。有关此示例,请参阅 elixir_locker。
另一种方法是序列化请求。这意味着,您将有一个进程,最好是 GenServer
,它将执行 SELECT+INSERT
。然后让您的进程向其发送消息,而不是自己查询数据库。这使得请求 运行 一个接一个,只有第一个请求会插入,其他请求会读取。当然,如果你有很多请求,这个过程本身可能会成为瓶颈。
我有多个并发任务,它们都试图检查记录是否存在,如果不存在,将插入一个。
不幸的是,我最终将记录重复写入数据库,因为似乎所有任务都决定同时不存在该记录,然后所有任务都进行插入。
期望的行为是我只得到一次插入,然后其他任务就会识别出刚刚插入的记录的存在。
这是我的尝试:
alias MyApp.Parent, as: Parent
alias MyApp.Repo, as: Repo
changeset = Parent.changeset(%Parent{}, model)
case Repo.all(from p in Parent, where: p.mobile_number == ^model.mobile_number) do
[] ->
#does not exist
case Repo.insert_or_update(changeset) do
{:ok, %MyApp.Parent{ id: parent_id }} -> parent_id
error_message -> nil
end
[parent_get_by|t] ->
#already exist
%MyApp.Parent{ id: parent_id }= parent_get_by
parent_id
end
感谢任何帮助!
您应该在数据库中为 mobile_number
字段添加一个 UNIQUE INDEX
。它会更有效率(您只需要对数据库执行一个查询)并且您可以保证数据库永远不会在 table.
您需要做三件事:
使用迁移将
unique_index
添加到 table。在您的变更集函数中添加对
unique_constraint
的调用。在您的控制器中,只需执行
Repo.insert(changeset)
。如果该字段重复,您将得到{:error, changeset}
返回并在changeset.errors
. 中显示错误消息
接受的答案很好。
但是当您不能强制执行唯一索引时,您有两种选择。首先是使用锁,以防止进程同时查询数据库。有关此示例,请参阅 elixir_locker。
另一种方法是序列化请求。这意味着,您将有一个进程,最好是 GenServer
,它将执行 SELECT+INSERT
。然后让您的进程向其发送消息,而不是自己查询数据库。这使得请求 运行 一个接一个,只有第一个请求会插入,其他请求会读取。当然,如果你有很多请求,这个过程本身可能会成为瓶颈。