MySQL中自增更新某一列会有线程安全问题嘛?

博客探讨了在MySQL中使用update语句进行并发更新时的线程安全问题。通过测试发现,单条update语句执行时没有线程安全问题,但多条语句或不同操作需要在事务中进行以确保数据一致性。实验涉及MVCC机制、MyBatis动态注解及in语句的使用,并展示了线程并发执行的输出结果。

同事突然问了一个这样的问题,自己写在代码里的更新语句

update virtual_assets set amount = amount +1 where user_id='test';

先说结论:没有线程安全问题
脑子突然想不明白,猜测可能不存在线程安全问题.还是自己实践一下最保险。(个人猜测和mysql的MVCC机制有关,网上也有说update会加排它锁,阻塞下一条update语句的执行)

@Update({"update virtual_assets",
            "set amount = amount + 1",
            "where user_id=#{userId}"
    })
    void addTest(@Param("userId") String userId);

    @Select({"select amount",
            "from virtual_assets",
            "where user_id = #{userId}"
    })
    Integer find(@Param("userId")String userId);

    @Update({"update virtual_assets",
            "set amount = #{amount}",
            "where user_id=#{userId}"
    })
    void add(@Param("userId") String userId,@Param("amount") Integer amount);

一种update的时候就加,一种先查再加。

@Test
    public void threadTest(){
        String userId= "test";
        String userId2= "test2";
        for(int i=0;i<100;i++){
            Thread thread = new Thread(() -> {
                virtualAssetsDao.addTest(userId);
                virtualAssetsDao.addTest2(userId2);
            });
            thread.start();
        }
        try {
            Thread.sleep(100000);
        } catch (Exception e){
            System.out.println("sssss");
        }
    }

注意test里多线程必须让主线程先等一下,不然主线程结束,子线程还没执行完也不会继续执行。
执行结果如下,初始值都是0,
在这里插入图片描述
一个语句的话没有线程安全问题,两个语句分开执行就有问题,需要开启事务才行。
然后又试了一下in语句,也同样没有问题。注意mybatis动态注解写in语句比较麻烦,可以参考in语句写法

@Update({
            "<script>",
            "update virtual_assets set amount = amount + 1 where user_id in ",
            "<foreach collection=\"userIds\" item=\"userId\" index=\"index\" open=\"(\" separator=\",\" close=\")\">",
            "#{userId}",
            "</foreach>",
            "</script>"
    })
    void addTest(@Param("userIds") List<String> userId);
@Test
    public void threadTest(){
        List<String> ids = new ArrayList<>();
        String userId= "test";
        String userId2= "test2";
        ids.add(userId);
        ids.add(userId2);
        //virtualAssetsDao.addTest(ids);
        for(int i=0;i<100;i++){
            int finalI = i;
            Thread thread = new Thread(() -> {
                virtualAssetsDao.addTest(ids);
                //virtualAssetsDao.addTest2(userId2);
                System.out.println(finalI);
            });
            thread.start();
        }
        try {
            Thread.sleep(100000);
        } catch (Exception e){
            System.out.println("sssss");
        }
    }

最后执行两次后数据库数据为
在这里插入图片描述
同时控制台输出
在这里插入图片描述
看到线程确实是乱序执行,但是最后的结果没问题。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值