关于 MySQL 中 SELECT 语句的原子性问题

乌小涂 发布于 08/19 11:12
阅读 2K+
收藏 3

解锁HarmonyOS核心技能,赢取限量周边好礼>>>

在MySQL数据库中存在一张settings表:

sname svalue
no 0
no2 0

同时存在以下两个函数:

CREATE FUNCTION `fn_inc_no`() RETURNS int(11)
BEGIN
    DECLARE val INT DEFAULT 0;
    
    UPDATE settings
    SET svalue = svalue + 1
    WHERE sname = 'no';
    
    SELECT svalue INTO val FROM settings WHERE sname = 'no';
    
    RETURN val;
END

CREATE DEFINER=`root`@`localhost` FUNCTION `fn_inc_no2`() RETURNS int(11)
BEGIN
    DECLARE val INT DEFAULT 0;
    
    UPDATE settings
    SET svalue = svalue + 1
    WHERE sname = 'no2';
    
    SELECT svalue INTO val FROM settings WHERE sname = 'no2';
    
    RETURN val;
END

如果此时在Java程序中运行如下代码:

Statement query = conn.createStatement();
ResultSet rs = query.executeQuery("SELECT fn_inc_no() AS no, fn_inc_no2() AS no2");

在多个线程(测试时使用了10个线程)中多次(测试时重复执行10000次)执行以上代码,最后得到的 no 和 no2 总是相等的。这是否说明了这条SELECT语句当中的fn_inc_no和fn_inc_no2总是在同一个事务中执行的,是否说明此条SELECT语句在MySQL中本身是一个原子操作?

加载中
1
红薯片
红薯片

no 和  no2是不同的数据行,同一个func里面的update, select也是顺序执行的啊。   这个完全不存在冲突的可能性啊

0
gqy2468
gqy2468

mysql里不同sql才有并发和锁的问题,同一sql内部不用考虑该类问题

0
冰力
冰力
换成 PostgreSQL 问题解决。
0
ArchitectureMaster
ArchitectureMaster

1.楼主在开启线程操作时有点小问题,如果你执行的代码是排它的那请加入synchronized关键字将你执行sql的代码包裹起来。

2.synchronized的特性决定只有一个线程能执行synchronized关键字的内容。

3.楼主的SQL也有问题,update后select只是放在一个function内这样是无法达到原子操作的。很简单,把update和select放到Tr主在开启线程操作时有点小问题,如果你执行的代码是排它的那请加入synchronized关键字将你执行sql的代码包裹起来。

 

4.synchronized的特性决定只有一个线程能执行synchronized关键字的内容。

 

5.楼主的SQL也有问题,update后select只是放在一个function内这样是无法达到原子操作的。很简单,把update和select放到Transaction中执行,只有在事务中的操作才是原子操作。

还有一点update后再select的表应该是inserted和deleted临时表里的记录,而不是直接取实表里的数据,这样由于实表数据如果很大会影响执行速度也没有必要。inserted表存储是update后的值,只需要在update之后select inserted表就可以了。

 

OSCHINA
登录后可查看更多优质内容
返回顶部
顶部