所有
我在我的应用程序中使用MySql 5.7。我试图使我的保存功能Concurrency Safe。我将用一个例子来解释。
示例: 我有两个管理员用户Admin 1和Admin 2.我们有一个产品表,我们有一个产品表条目,产品代码" P1"。假设Admin 1和Admin 2已登录到系统并尝试使用代码" P1"更新产品条目。同时。
我需要通知其中一位用户您正在尝试修改的记录正在由其他用户更新,并在一段时间后重试。
我正在使用事务并且没有更改MySql的默认事务级别(可重复读取)。我试图通过使用" SELECT FOR UPDATE"(包括用修改时间检查的where条件)来解决它。这"其中" condition将解决已经提交的事务的并发问题。但是如果两个事务同时启动并且第一个事务在锁定超时之前提交,那么当第二个事务执行时,它会覆盖第一个事务。
请分享您的想法
提前致谢
答案 0 :(得分:3)
这里实际上有两个问题。
首先,其中一个管理员将在另一个之前锁定该行,因此假设admin1首先获得锁定,admin2将排队直到admin1的事务完成,然后admin2的事务将发生。
所以这一切都由DBMS为您照顾。
但第二个问题当然是admin1和admin2都试图更新同一列。在这种情况下,admin1的更新将被admin2的更新覆盖。阻止这种情况发生的唯一方法就是让你想要停止的是使更新非常具体。换句话说,UPDATE必须是这样的
UPDATE table SET col1 = 'NewValue'
WHERE usual criteria
AND col1 = 'Its Original Value'
因此,这意味着当您将此行中的原始数据呈现给表单中的用户时,您必须以某种方式记住其原始状态以及捕获管理员将其更改为的新状态。
当然,还必须编写PHP代码以捕获UPDATE未发生的事实,并向管理员的更新现在失败返回一些内容。显示相关列中的新值,并通知他们更新失败,因为其他人已经更改了该字段,并让他们忘记更改,或者将更改应用于其他管理员更新的顶部。
答案 1 :(得分:0)
您可以使用此技术来控制它,而无需锁定表或控制应该执行的更新。
在您的表上创建一个将成为该注册表版本的字段:
alter table someTable add column version not null integer default 0;
无需使用此更改任何插入代码。
每次用户提取注册表以进行更新时,请确保它还具有对象中的版本(或表单,m或您在系统中处理实体的任何方式)。
然后,您需要为您的表创建一个before update trigger
,以检查当前注册表的版本是否仍然相同,如果您没有引发错误,则更新。类似的东西:
delimiter $$
create trigger trg_check_version BEFORE UPDATE
ON yourTable
for each row
begin
if NEW.version != OLD.version then
signal sqlstate '45000' set message_text = 'Field outdated';
else
NEW.version = NEW.version + 1;
end if;
end$$
delimiter;
然后你处理PHP代码中的错误。此signal
命令仅适用于MySql 5.5或更高版本。看看这个thread