zoukankan      html  css  js  c++  java
  • 遇到线程安全问题的案例

    web项目中每个请求都是一个新的线程,如下代码,在不同的service层中操作相同的数据时,会出现线程安全问题。具体表现是:设定 sms初始值为10,smsUsed初始值为0;则两个请求分别同时访问test方法和testB方法时,两个方法中输出的结果显示:sms:9 smsUsed:1;按照正常的业务逻辑来说,当两个请求都完成后,sms应该为8,smsUsed为2。

    @Override
        @Transactional(propagation = Propagation.REQUIRED,rollbackFor = Exception.class)
        public void test(){
            Long hid = 6L;
            Saler saler = salerDAO.getSalerBySid(hid);
            Long sms = saler.getSmsUnused();
            sms--;
            Long smsUsed = saler.getSmsUsed();
            smsUsed++;
            System.out.println("test ##### sms:"+ sms +" smsUsed:" + smsUsed);
            try {
                Thread.sleep(15000);
            }catch (Exception e) {
                throw new SelectNoFindException("test睡眠报错了",null);
            }
            salerDAO.updateSalerSms(hid, sms, smsUsed);
            System.out.println("test ##### sms:"+ sms +" smsUsed:" + smsUsed);
        }
    
        @Override
        @Transactional(propagation = Propagation.REQUIRED,rollbackFor = Exception.class)
        public void testB(){
            Long hid = 6L;
            Saler saler = salerDAO.getSalerBySid(hid);
            Long sms = saler.getSmsUnused();
            sms--;
            Long smsUsed = saler.getSmsUsed();
            smsUsed++;
            salerDAO.updateSalerSms(hid, sms, smsUsed);
            System.out.println("testB ##### sms:"+ sms +" smsUsed:" + smsUsed);
        }
    View Code

    解决方案: 

      方案1.将两个方法合并成一个,在获取和修改共享数据时加锁。

      方案2.因为两个方法中修改共享数据的sql是相同的,所以可以使用数据库的行级锁(排它锁),在查询共享数据的sql语句后面加上 “for update”;

  • 相关阅读:
    棋盘完美覆盖数(小规模原理实现)
    Codeforces 115A Party (并查集思维)
    datetime日期和时间
    range与enumerate的区别
    爬取爱套图网上的图片
    python爬取365好书中小说
    列表和元组的方法
    字符串中的方法
    从电源问题出发,带你揭秘新体系结构范式 COA
    KubeCon 2020 演讲集锦|《阿里巴巴云原生技术与实践 13 讲》开放下载
  • 原文地址:https://www.cnblogs.com/zhlblogs/p/12674709.html
Copyright © 2011-2022 走看看