我有两个innodb表:
文章
id | title | sum_votes
------------------------------
1 | art 1 | 5
2 | art 2 | 8
3 | art 3 | 35
票数
id | article_id | vote
------------------------------
1 | 1 | 1
2 | 1 | 2
3 | 1 | 2
4 | 2 | 10
5 | 2 | -2
6 | 3 | 10
7 | 3 | 15
8 | 3 | 12
9 | 3 | -2
将新记录插入votes
表中时,我想通过计算所有投票的总和来更新表中的sum_votes
字段articles
。
如果SUM()计算本身非常votes
繁琐(表有700K条记录),则哪种方法更有效。
1.创建触发器
CREATE TRIGGER `views_on_insert`
AFTER INSERT
ON `votes`
FOR EACH ROW
BEGIN
UPDATE `articles` SET
sum_votes = (
SELECT SUM(`vote`)
FROM `votes`
WHERE `id` = NEW.article_id
)
WHERE `id` = NEW.article_id;
END;
2.在我的应用程序中使用两个查询
SELECT SUM(`vote`) FROM `votes` WHERE `article_id` = 1;
UPDATE `articles`
SET sum_votes = <1st_query_result>
WHERE `id` = 1;
第一种方法看起来更干净,但是 在整个SELECT查询运行期间,表是否将被锁定?
关于并发问题,您有一种 “简便”的 方法来防止第二种方法中的任何并发问题,在事务内部,在商品行上执行选择(For update
现在是隐式的)。同一篇文章上的任何并发插入将无法获得此相同的锁,并且将等待您。
使用新的默认隔离级别,甚至在事务中甚至不使用序列化级别,您都不会在投票表上看到任何并发插入,直到事务结束。因此,您的SUM应该保持连贯性
或看起来像连贯性
。但是,如果并发事务在同一文章上插入一个投票并在您之前提交(而第二个事务看不到您的插入),则最后一次提交的事务将覆盖计数器,您将失去1票。
因此,请使用之前的select方法对文章进行行锁定
(当然,并在事务中完成您的工作)。它很容易测试,可以在MySQL上打开2个交互式会话,并使用BEGIN开始交易。
如果使用触发器,则默认情况下您处于事务中。但是我认为您也应该在商品表上执行选择,以为运行中的并发触发器创建隐式行锁(难以测试)。
最后一点:在开始使用交易之前,进行更困难的交易:
SET TRANSACTION ISOLATION LEVEL SERIALIZABLE;
这样,您不需要对文章进行行锁定,MySQL将检测到同一行上可能发生的写入,并会阻塞其他事务,直到您完成操作为止。
但是,请勿使用您根据上一个请求计算出的内容
。更新查询将等待商品的锁释放,当第一个事务释放锁时COMMIT
,SUM
应该再次进行计算。因此,更新查询应包含SUM
或进行添加。
update articles set nb_votes=(SELECT count(*) from vote) where id=2;
在这里,您会看到MySQL很聪明,如果在同时执行插入操作的同时有2个事务试图执行此操作,则会检测到死锁。在序列化级别中,我还没有找到一种使用以下方法获得错误值的方法:
SET TRANSACTION ISOLATION LEVEL SERIALIZABLE;
BEGIN;
insert into vote (...
update articles set nb_votes=(
SELECT count(*) from vote where article_id=xx
) where id=XX;
COMMIT;
但是请准备好处理您必须重做的突破性交易。
本文向大家介绍详解MySQL(InnoDB)是如何处理死锁的,包括了详解MySQL(InnoDB)是如何处理死锁的的使用技巧和注意事项,需要的朋友参考一下 一、什么是死锁 官方定义如下:两个事务都持有对方需要的锁,并且在等待对方释放,并且双方都不会释放自己的锁。 这个就好比你有一个人质,对方有一个人质,你们俩去谈判说换人。你让对面放人,对面让你放人。 二、为什么会形成死锁 看到这里,也许你会有这样
本文向大家介绍InnoDB数据库死锁问题处理,包括了InnoDB数据库死锁问题处理的使用技巧和注意事项,需要的朋友参考一下 场景描述 在update表的时候出现DeadlockLoserDataAccessException异常 (Deadlock found when trying to get lock; try restarting transaction...)。 问题分析 这个异常并不会
我希望能够用REST控制器开始我的作业,然后当作业开始时,它应该在计划的基础上运行,直到我用REST再次停止它。
我的服务api接收quartz作业的startDate和要执行的作业的day。在内部,我将其转换为cron表达式并保存在Quartz中。 例如,PST中的一个用户今天(2017年11月3日)提交了一个作业请求,如下所示。 在这里,用户希望从2017-11-03开始,在每月15日下午6点启动一个工作。所以石英的第一天将在2017-11-15。以上请求是如何转换为cron表达式,这是正确的。下面是QR
问题内容: 如何保证我可以搜索数据库中是否存在用户名,然后将该用户名作为新行插入数据库中,而and 语句之间没有任何截距? 几乎就像我锁在不存在的行上。我想用用户名 “ Foo” 锁定不存在的行,以便现在可以检查数据库中是否存在该行,并将其插入数据库(如果尚不存在的话)将其插入数据库。 我知道使用和存在,但据我所知,仅适用于已经存在的行。我不确定在这种情况下该怎么办。 问题答案: 如果存在索引(应
如何保证我可以搜索我的数据库中是否存在用户名,然后将该用户名作为新行插入数据库,而不会在和语句之间进行任何拦截? 几乎就像我锁定了一个不存在的行。我想用用户名“Foo”锁定不存在的行,这样我现在可以检查它是否存在于数据库中,如果它还不存在,就可以将它插入数据库中,而不会出现任何中断。 我知道使用< code>LOCK IN SHARE MODE和< code>FOR UPDATE是存在的,但是据我