spring事物隔離級別和mybatis快取的問題
阿新 • • 發佈:2019-01-25
今天使用@Transactional遇到了問題,通過一些實驗,總結下自己的想法。如有不當歡迎指正~
專案使用spring boot + mybatis + mysql,先上程式碼:
@Override @Transactional public void test(){ UDeptDO dept = uDeptDao.get("0cf58a5d6ae811e89feafa163eb3e537"); // 列印舊值 log.info("deptname={}", dept.getDeptname()); try { Thread.sleep(5000); } catch (InterruptedException e) { } dept.setDeptname("test"); update(dept); dept = uDeptDao.get("0cf58a5d6ae811e89feafa163eb3e537"); // 列印新值 log.info("deptname={}", dept.getDeptname()); try { Thread.sleep(10000); } catch (InterruptedException e) { } } @Override @Transactional(isolation = Isolation.READ_COMMITTED) public void test1(){ UDeptDO dept = uDeptDao.get("0cf58a5d6ae811e89feafa163eb3e537"); // 列印舊值 log.info("deptname={}", dept.getDeptname()); try { Thread.sleep(10000); } catch (InterruptedException e) { } // 列印舊值,事物未提交 dept = uDeptDao.get("0cf58a5d6ae811e89feafa163eb3e537"); log.info("deptname={}", dept.getDeptname()); try { Thread.sleep(10000); } catch (InterruptedException e) { } // 列印新值,事物已提交,READ_COMMITTED生效 dept = uDeptDao.get("0cf58a5d6ae811e89feafa163eb3e537"); log.info("deptname={}", dept.getDeptname()); }
以上是一個service實現類的兩個測試方法,方法test使用Spring事物的預設隔離級別(也就是由底層資料庫提供的隔離級別,mysql預設是REPEATABLE_READ),方法test1使用READ_COMMITTED。同時呼叫test和test1,預期test1方法第三次查詢能獲取到修改值,但是並沒有成功(此處糾結了好久,還以為自己理解錯了。。。)。分析日誌發現test1後兩次查詢未列印SQL語句,估計是快取的原因。給mapper檔案的查詢語句加上useCache="false" flushCache="true"這兩個配置,問題解決。
從這個例子可以看到,READ_COMMITTED可以避免dirty reads,即test1第二次查詢不會查到test的修改,只有test方法事物提交後,test1在第三次查詢才能看到。這裡test1方法後兩次的查詢行為,其實就是我們常說的non-repeatable reads。如果使用REPEATABLE_READ級別,能使test1的三次查詢結果保持一致。