1. 程式人生 > 實用技巧 >mybatis樂觀鎖重試機制

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