我有一个在MySQL,Hibernate和Spring管理的事务上运行的java应用程序。
有一个特定的交易让我担心一点。我尝试设置一些并发测试环境(使用ApacheBench),测试似乎没问题,但我还是有些疑惑......
事务逻辑沿着这些方向(使用混合的sql +伪代码,为简洁起见):
updated = 0;
// lock counter row, if exists
selected = select x from tbl1 where [composite PK match] FOR UPDATE;
if(selected == null) {
// Record does not exist... I thought this might be a good idea, as there will be only
// one insert for the given PK daily and many subsequent updates (rather do this than
// forcing 'insert...on duplicate key update' constantly?)
updated = insert into tbl1 values(...) on duplicate key update cnt = cnt + 1;
} else {
// Record exists, just increment the counter.
updated = update tbl1 set cnt = cnt + 1;
}
return updated;
表tbl1
是这样的:
create table tbl1 (
`a_id` int(11) NOT NULL,
`b_id` int(11) NOT NULL,
`c_id` int(11) NOT NULL,
`day` date NOT NULL,
`cnt` int(11) DEFAULT '0',
PRIMARY KEY (`a_id`,`b_id`,`c_id`,`day`)
) ENGINE=InnoDB;
事务隔离是MySQL的默认值(REPEATABLE READ
)。
对我来说最重要的是:
...我还想添加两个相关的子问题:
在这个表上增加一个计数器:update tbl1 set c = c + 1 where [match row by composite PK]
线程安全/原子/一致吗?
根据我的测试,它是。根据{{3}},它可能取决于......如果是,我猜上面的逻辑可以进一步优化/简化,因此它不会使用select...for update
(我只是为了安全而添加它侧)。
如果select...where...for update
作为第一个语句在事务中执行,但没有匹配WHERE
子句的记录,那么这可能会导致一些隐藏的行级锁定,之后的DML语句可能会使用相同的匹配条件(如示例中)执行,以及这可能会如何影响其他并发事务?