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”;

  • 相关阅读:
    校内题目T2695 桶哥的问题——吃桶
    一位大佬对学习哲理的思考
    P2845 [USACO15DEC]Switching on the Lights 开关灯
    CF911F Tree Destruction
    CF995C Leaving the Bar
    CF997B Roman Digits
    P1667 数列
    P4035 [JSOI2008]球形空间产生器
    P2679 子串
    P2613 【模板】有理数取余
  • 原文地址:https://www.cnblogs.com/zhlblogs/p/12674709.html
Copyright © 2011-2022 走看看