zoukankan      html  css  js  c++  java
  • mybatis乐观锁重试机制

    MyBatis实现乐观锁遇到的问题

    1. MyBatis缓存(一级缓存)

    问题:MyBatis在查询时,会将结果放入缓存中,导致再次查询相同的Sql的结果不是数据库中最新的值
    解决方案:在statement上加上flushCache="true"

    <select id="getFromDb" flushCache="true" resultType="xxx">
        select
        *
        from device
        where id = #{id,jdbcType=BIGINT}
    </select>

    2. 事物隔离级别

    问题:由于Mysql默认的事物隔离级别是repeatable read,导致读取不到其他事物提交的最新的值
    解决方案:修改为read committed

    @Transactional(isolation = Isolation.READ_COMMITTED)
    public Device getFromDb(long id) {
        return deviceMapper.getFromDb(id);
    }

    3. 事物传播机制

    问题:如果2中的方法是在其他Service中调用的。而其他的Service使用了事务,并且和2中的隔离级别不一样,可能会导致2中设置的隔离级别被覆盖。
    解决方案:使用子事务执行

    @Transactional(isolation = Isolation.READ_COMMITTED, propagation = Propagation.REQUIRES_NEW)
    public Device getFromDb(long id) {
        return deviceMapper.getFromDb(id);
    }

    测试类

    public class ThreadHttpTest {
    
        public static String doPost(String url, Map<String, String> mapParams) {
            try (CloseableHttpClient httpclient = HttpClients.createDefault()) {
                HttpPost httpPost = new HttpPost(url);
    
                //封装请求参数
                if (mapParams != null) {
                    List<BasicNameValuePair> list = new ArrayList<>();
                    for (Map.Entry<String, String> entry : mapParams.entrySet()) {
                        list.add(new BasicNameValuePair(entry.getKey(), entry.getValue()));
                    }
                    UrlEncodedFormEntity formEntity = new UrlEncodedFormEntity(list, "utf-8");
                    formEntity.setContentType("Content-Type:application/json");
                    httpPost.setEntity(formEntity);
                }
    
                try (CloseableHttpResponse response = httpclient.execute(httpPost)) {
                    return EntityUtils.toString(response.getEntity());
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
            return null;
        }
    
        public static void main(String[] args) {
            ExecutorService threadPool = Executors.newFixedThreadPool(20);
            for (int i = 0; i < 20; i++) {
                threadPool.execute(() -> {
                    String name = Thread.currentThread().getName();
                    String r = doPost("http://localhost:8086/t", null);
                    System.out.println(name + ":" + r);
                });
            }
            threadPool.shutdown();
        }
    }

    controller

        @RequestMapping(value = "/t")
        @ResponseBody
        public String t() {
            productService.t();
            return new Date().toString();
        }

    service (备注:sales就是version字段,isRecommend就是要更新的数据,只是拿手头上临时的类写的demo)

        @Transactional(rollbackFor = Exception.class, isolation = Isolation.READ_COMMITTED)
        @Override
        public void t() {
            String name = Thread.currentThread().getName();
    
            //无限重试,直到成功
    //        int num = 0;
    //        while (num == 0) {
    //            Product p = this.findById(43L);
    //            System.out.println("=====" + name + "人数:" + p.getIsRecommend());
    //            System.out.println("=====" + name + "版本号:" + p.getSales());
    //
    //            if (p.getIsRecommend() == 5) {
    //                System.out.println("=====" + name + "人数已满:" + p.getIsRecommend());
    //                break;
    //            }
    //
    //            num = productService.updateT(43L, p.getSales());
    //            System.out.println("=====" + num);
    //            if (num == 0) {
    //                System.out.println("=====更新失败=====" + name + ":" + num);
    //            }
    //            if (num == 1) {
    //                System.out.println("=====更新成功=====" + name + ":" + num);
    //            }
    //        }
    
    
            //最多尝试3次
            for (int i = 0; i < 3; i++) {
                Product p = this.findById(43L);
                System.out.println("=====" + name + "人数:" + p.getIsRecommend());
                System.out.println("=====" + name + "版本号:" + p.getSales());
    
                if (p.getIsRecommend() == 5) {
                    System.out.println("=====" + name + "人数已满:" + p.getIsRecommend());
                    break;
                }
    
                int num = productService.updateT(43L, p.getSales());
                System.out.println("=====" + num);
                if (num == 0) {
                    System.out.println("=====更新失败=====" + name + ":" + (i + 1) + "次");
                }
                if (num == 1) {
                    System.out.println("=====更新成功=====" + name + ":" + num);
                    break;
                }
            }
        }

    XML

        <update id="updateT">
            update product
            set is_recommend = is_recommend + 1,
                sales = sales + 1
            where id = #{id}
            and sales = #{version};
        </update>

    日志分析

    最多尝试3次日志

    =====http-nio-8086-exec-13人数:0
    =====http-nio-8086-exec-13版本号:0
    =====http-nio-8086-exec-6人数:0
    =====http-nio-8086-exec-6版本号:0
    =====http-nio-8086-exec-20人数:0
    =====http-nio-8086-exec-20版本号:0
    =====http-nio-8086-exec-16人数:0
    =====http-nio-8086-exec-16版本号:0
    =====http-nio-8086-exec-9人数:0
    =====http-nio-8086-exec-9版本号:0
    =====http-nio-8086-exec-5人数:0
    =====http-nio-8086-exec-5版本号:0
    =====1
    =====更新成功=====http-nio-8086-exec-9:1
    =====0
    =====更新失败=====http-nio-8086-exec-5:1次
    =====http-nio-8086-exec-5人数:1
    =====http-nio-8086-exec-5版本号:1
    =====1
    =====更新成功=====http-nio-8086-exec-5:1
    =====0
    =====更新失败=====http-nio-8086-exec-6:1次
    =====http-nio-8086-exec-6人数:2
    =====http-nio-8086-exec-6版本号:2
    =====http-nio-8086-exec-15人数:2
    =====http-nio-8086-exec-15版本号:2
    =====1
    =====更新成功=====http-nio-8086-exec-6:1
    =====0
    =====更新失败=====http-nio-8086-exec-13:1次
    =====http-nio-8086-exec-13人数:3
    =====http-nio-8086-exec-13版本号:3
    =====http-nio-8086-exec-11人数:3
    =====http-nio-8086-exec-11版本号:3
    =====http-nio-8086-exec-17人数:3
    =====http-nio-8086-exec-17版本号:3
    =====1
    =====更新成功=====http-nio-8086-exec-13:1
    =====0
    =====更新失败=====http-nio-8086-exec-20:1次
    =====http-nio-8086-exec-20人数:4
    =====http-nio-8086-exec-20版本号:4
    =====http-nio-8086-exec-21人数:4
    =====http-nio-8086-exec-21版本号:4
    =====1
    =====更新成功=====http-nio-8086-exec-20:1
    =====0
    =====更新失败=====http-nio-8086-exec-16:1次
    =====http-nio-8086-exec-16人数:5
    =====http-nio-8086-exec-16版本号:5
    =====http-nio-8086-exec-16人数已满:5
    =====0
    =====更新失败=====http-nio-8086-exec-15:1次
    =====http-nio-8086-exec-4人数:5
    =====http-nio-8086-exec-4版本号:5
    =====http-nio-8086-exec-4人数已满:5
    =====http-nio-8086-exec-15人数:5
    =====http-nio-8086-exec-15版本号:5
    =====http-nio-8086-exec-15人数已满:5
    =====0
    =====更新失败=====http-nio-8086-exec-11:1次
    =====http-nio-8086-exec-11人数:5
    =====http-nio-8086-exec-11版本号:5
    =====http-nio-8086-exec-11人数已满:5
    =====0
    =====更新失败=====http-nio-8086-exec-17:1次
    =====http-nio-8086-exec-17人数:5
    =====http-nio-8086-exec-17版本号:5
    =====http-nio-8086-exec-17人数已满:5
    =====0
    =====更新失败=====http-nio-8086-exec-21:1次
    =====http-nio-8086-exec-12人数:5
    =====http-nio-8086-exec-12版本号:5
    =====http-nio-8086-exec-12人数已满:5
    =====http-nio-8086-exec-21人数:5
    =====http-nio-8086-exec-21版本号:5
    =====http-nio-8086-exec-21人数已满:5
    =====http-nio-8086-exec-7人数:5
    =====http-nio-8086-exec-7版本号:5
    =====http-nio-8086-exec-7人数已满:5
    =====http-nio-8086-exec-2人数:5
    =====http-nio-8086-exec-2版本号:5
    =====http-nio-8086-exec-2人数已满:5
    =====http-nio-8086-exec-14人数:5
    =====http-nio-8086-exec-14版本号:5
    =====http-nio-8086-exec-14人数已满:5
    =====http-nio-8086-exec-1人数:5
    =====http-nio-8086-exec-1版本号:5
    =====http-nio-8086-exec-1人数已满:5
    =====http-nio-8086-exec-19人数:5
    =====http-nio-8086-exec-19版本号:5
    =====http-nio-8086-exec-19人数已满:5
    =====http-nio-8086-exec-18人数:5
    =====http-nio-8086-exec-18版本号:5
    =====http-nio-8086-exec-18人数已满:5
    =====http-nio-8086-exec-3人数:5
    =====http-nio-8086-exec-3版本号:5
    =====http-nio-8086-exec-3人数已满:5
    =====http-nio-8086-exec-8人数:5
    =====http-nio-8086-exec-8版本号:5
    =====http-nio-8086-exec-8人数已满:5

    无限尝试直到成功日志

    =====http-nio-8086-exec-19人数:0
    =====http-nio-8086-exec-19版本号:0
    =====http-nio-8086-exec-3人数:0
    =====http-nio-8086-exec-3版本号:0
    =====http-nio-8086-exec-11人数:0
    =====http-nio-8086-exec-11版本号:0
    =====http-nio-8086-exec-15人数:0
    =====http-nio-8086-exec-15版本号:0
    =====1
    =====更新成功=====http-nio-8086-exec-19:1
    =====0
    =====更新失败=====http-nio-8086-exec-15:0
    =====http-nio-8086-exec-23人数:0
    =====http-nio-8086-exec-23版本号:0
    =====0
    =====更新失败=====http-nio-8086-exec-11:0
    =====http-nio-8086-exec-15人数:1
    =====http-nio-8086-exec-15版本号:1
    =====0
    =====更新失败=====http-nio-8086-exec-23:0
    =====http-nio-8086-exec-11人数:1
    =====http-nio-8086-exec-11版本号:1
    =====0
    =====更新失败=====http-nio-8086-exec-3:0
    =====http-nio-8086-exec-23人数:1
    =====http-nio-8086-exec-23版本号:1
    =====http-nio-8086-exec-22人数:1
    =====http-nio-8086-exec-22版本号:1
    =====http-nio-8086-exec-3人数:1
    =====http-nio-8086-exec-3版本号:1
    =====1
    =====更新成功=====http-nio-8086-exec-11:1
    =====http-nio-8086-exec-14人数:1
    =====http-nio-8086-exec-14版本号:1
    =====0
    =====更新失败=====http-nio-8086-exec-15:0
    =====http-nio-8086-exec-15人数:2
    =====http-nio-8086-exec-15版本号:2
    =====http-nio-8086-exec-24人数:2
    =====http-nio-8086-exec-24版本号:2
    =====1
    =====更新成功=====http-nio-8086-exec-15:1
    =====http-nio-8086-exec-25人数:2
    =====http-nio-8086-exec-25版本号:2
    =====0
    =====更新失败=====http-nio-8086-exec-23:0
    =====http-nio-8086-exec-23人数:3
    =====http-nio-8086-exec-23版本号:3
    =====1
    =====更新成功=====http-nio-8086-exec-23:1
    =====0
    =====更新失败=====http-nio-8086-exec-22:0
    =====http-nio-8086-exec-26人数:4
    =====http-nio-8086-exec-26版本号:4
    =====http-nio-8086-exec-22人数:4
    =====http-nio-8086-exec-22版本号:4
    =====1
    =====更新成功=====http-nio-8086-exec-22:1
    =====0
    =====更新失败=====http-nio-8086-exec-3:0
    =====http-nio-8086-exec-8人数:5
    =====http-nio-8086-exec-8版本号:5
    =====http-nio-8086-exec-8人数已满:5
    =====http-nio-8086-exec-3人数:5
    =====http-nio-8086-exec-3版本号:5
    =====http-nio-8086-exec-3人数已满:5
    =====0
    =====更新失败=====http-nio-8086-exec-14:0
    =====http-nio-8086-exec-14人数:5
    =====http-nio-8086-exec-14版本号:5
    =====http-nio-8086-exec-14人数已满:5
    =====http-nio-8086-exec-27人数:5
    =====http-nio-8086-exec-27版本号:5
    =====http-nio-8086-exec-27人数已满:5
    =====0
    =====更新失败=====http-nio-8086-exec-24:0
    =====http-nio-8086-exec-24人数:5
    =====http-nio-8086-exec-24版本号:5
    =====http-nio-8086-exec-24人数已满:5
    =====0
    =====更新失败=====http-nio-8086-exec-25:0
    =====http-nio-8086-exec-25人数:5
    =====http-nio-8086-exec-25版本号:5
    =====http-nio-8086-exec-25人数已满:5
    =====0
    =====更新失败=====http-nio-8086-exec-26:0
    =====http-nio-8086-exec-26人数:5
    =====http-nio-8086-exec-26版本号:5
    =====http-nio-8086-exec-26人数已满:5
    =====http-nio-8086-exec-12人数:5
    =====http-nio-8086-exec-12版本号:5
    =====http-nio-8086-exec-12人数已满:5
    =====http-nio-8086-exec-28人数:5
    =====http-nio-8086-exec-28版本号:5
    =====http-nio-8086-exec-28人数已满:5
    =====http-nio-8086-exec-18人数:5
    =====http-nio-8086-exec-18版本号:5
    =====http-nio-8086-exec-18人数已满:5
    =====http-nio-8086-exec-29人数:5
    =====http-nio-8086-exec-29版本号:5
    =====http-nio-8086-exec-29人数已满:5
    =====http-nio-8086-exec-32人数:5
    =====http-nio-8086-exec-32版本号:5
    =====http-nio-8086-exec-32人数已满:5
    =====http-nio-8086-exec-30人数:5
    =====http-nio-8086-exec-30版本号:5
    =====http-nio-8086-exec-30人数已满:5
    =====http-nio-8086-exec-1人数:5
    =====http-nio-8086-exec-1版本号:5
    =====http-nio-8086-exec-1人数已满:5
    =====http-nio-8086-exec-31人数:5
    =====http-nio-8086-exec-31版本号:5
    =====http-nio-8086-exec-31人数已满:5
  • 相关阅读:
    .net从网络接口地址获取json,然后解析成对象(一)
    .net获取本地ip地址
    .net上传文件,利用npoi读取文件信息到datatable里
    .net利用NPOI生成excel文件
    .NET获取城市信息(将三字代码转换成城市名)
    JS下拉页面时一个横幅的样式和js
    整数中1出现的次数(1~n)
    连续子数组的最大和
    最小的K个数
    数组中出现次数超过一半的数字
  • 原文地址:https://www.cnblogs.com/xiaomaoyvtou/p/13376832.html
Copyright © 2011-2022 走看看