MySQL Query是否包含子查询原子?

时间:2011-04-28 08:53:32

标签: mysql

有两个表:

表1唯一会话

ID    Count 

表2(会话)

ID    Name

我想更新count只有当会话中不存在name才能计算唯一会话时,这是一个例子,所以客观不是通过其他方式来做,但问题是:< / p>

Rowsaffected = Update table1 
                   set Count = Count + 1 
               where (Select count(*) from table2 where Name = 'user1' ) = 0;

Insert into table2 (NAME) values('user');

首先查询原子查询?如果是,则没有问题。

如果不是,那么如果有多个线程运行来执行上述操作怎么办?有可能:

线程1:count返回0,它在线程2启动之前更新了表1但没有更新表2。 线程2:它找到计数0,它也将更新计数。

现在对于同一个用户,count是2,不应该发生。

任何建议/反馈。

4 个答案:

答案 0 :(得分:1)

这取决于您使用的存储引擎。

您的示例仅适用于支持事务的MySQL引擎,如InnoDB,因为它正确实现了事务处理(以及语句级读取一致性)

MyISAM不支持交易。

答案 1 :(得分:0)

参考:Mysql Internel Manual

因此,MySQL采用嵌套事务机制为标准所需的SQL语句提供“全有或全无”保证。 MySQL会在每个SQL语句的开头创建一个嵌套事务,并在语句结束时销毁(提交或中止)该嵌套事务。 MySQL人们内部将这种嵌套事务称为“语句事务”。这就是“陈述交易”一词的诞生。

根据我自己的理解,我认为嵌套的sql是MySQL原子的。

答案 2 :(得分:0)

最好使用exists子句: https://dev.mysql.com/doc/refman/8.0/en/exists-and-not-exists-subqueries.html

Rowsaffected = Update table1 set Count = Count + 1 where NOT EXISTS (Select ID from table2 where Name = 'user1' );

仅针对您问题的原子部分的参考,但可以肯定的是,您可以将两个语句都包装在一个事务中。 虽然根据您的并发模型,您可能希望提高事务隔离级别,但这看起来并不是绝对必要的。

MySQL 将语句视为原子的 https://dev.mysql.com/doc/refman/8.0/en/mysql-acid.html

从技术上讲,子查询是它们出现的语句的一部分。 https://dev.mysql.com/doc/refman/8.0/en/expressions.html 尽管在语法上与独立语句相似,但它们是单独运行的 - 优化器将整个语句视为一个工作单元。

这确实假设您使用的是支持事务的存储引擎: https://dev.mysql.com/doc/refman/8.0/en/storage-engines.html (在页面底部表格的末尾)

隔离级别要求在查询运行时获取的读锁将一直保留到写锁被获取并且所有锁将一起释放。 https://dev.mysql.com/doc/refman/8.0/en/innodb-transaction-isolation-levels.html

(虽然文档似乎没有明确说明这一点,否则无法保证隔离级别)

答案 3 :(得分:-1)

不确定我是否理解要求,但是如果您希望获得唯一的会话计数,则只需要一个表。对于table2,将用户添加为主键(如果尚未添加):

ALTER TABLE table2添加用户PRIMARY KEY;

然后使用INSERT IGNORE,仅在用户不存在时插入:

在表2中插入IGNORE (名称) 价值 (“用户”);

然后您可以通过“从table2中选择count(*)”来获得唯一的会话。