只讀事務為了擴大事務的范圍(single sql -》 java function),解決多次select不相等(即不可重復讀)的問題;相當於在外面蓋了一個整體的rr的隔離級別
注意隔離級別不是只讀事務的目標,因為即使autocommit true,也有事務隔離級別可單獨設定,只不過是對於single sql而言 work log 2020.4.7 1)
rr級別事務,帶update insert delete | 只讀事務 | 普通讀 | |
autocommit | false | false | default true |
設置隔離級別 | rr | rr | 自行設定,默認rr |
圖
=============================================================================================================================
2020.10.14 該理解有問題
並不是只讀了,就rr了,也可以只讀rc,只是只讀事務讓同一個方法中所有sql共享一個事務號,可配合rr級別,共享readview來避免重復讀 mvcc巨無霸【重點】
=============================================================================================================================
事務的2步走:
autocommit fasle,宣告一個事務號,(一個連接是一個事務的充分非必要條件),開始【享受】
set 隔離級別
【享受】:(同中work log中2020.4.7 2)黃色背景的3點)
因為共享了事務號(mvcc巨無霸【重點】),事務內select無條件可見性:work log
同一事務內鎖共享【注釋死鎖】
rr(如果不在一個事務中,那rr這種級別無法實現,如圖中第4列),【可重復讀實踐】
【注釋死鎖】
con1 開啟 transaction,set autocommit false
con1 select for update,獲取鎖x
con2 update
con2 等待鎖x——死鎖
con1 commit
1【可重復讀實踐】
/** * https://www.cnblogs.com/silyvin/p/12657283.html * ScefOrmSession * private List<Map<String, Object>> query(String sql) { * & jdbcUtil = utilThreadLocal.get(); & if(jdbcUtil == null) jdbcUtil = jdbcPool.borrowObject(); * @return */ @RequestMapping(value = "rr") @ResponseBody public TestOrmImpl rr() { ScefOrmSession scefOrmSession = new ScefJoinOrmSession(); TestOrmImpl orm = new TestOrmImpl(); orm.setId(1); try { scefOrmSession.startTransaction(); scefOrmSession.clearCache(); orm = (TestOrmImpl)scefOrmSession.queryForObject(orm); System.out.println(orm.getDoubleField()); Thread.sleep(5000); /** * 手動修改doubleField */ scefOrmSession.clearCache(); orm = (TestOrmImpl)scefOrmSession.queryForObject(orm); System.out.println(orm.getDoubleField()); scefOrmSession.commit(); } catch (Exception e) { scefOrmSession.rollback(); } finally { scefOrmSession.endTransaction(); } return orm; }
(a)第一種情況,2次io不用同一個連接,分別從池里拿,兩次連接都是默認autocommit true,各自有各自事務號
private List<Map<String, Object>> query(String sql) {
AbstractJdbcUtil jdbcUtil = null;
GenericObjectPool<AbstractJdbcUtil> jdbcPool = null;
List list = null;
try {
jdbcPool = getJdbcPool();
// jdbcUtil = utilThreadLocal.get();
// if(jdbcUtil == null)
jdbcUtil = jdbcPool.borrowObject();
list = jdbcUtil.queryForList(sql);
} catch (Exception e) {
throw new DBException(e);
} finally {
if(jdbcUtil != null // && utilThreadLocal.get() == null)
jdbcPool.returnObject(jdbcUtil);
}
return list;
}
結果2次打印不一樣
(b)第二種情況,將藍色注釋放開,都取threadlocal中那個連接:
public void startTransaction() { AbstractJdbcUtil util = null; try { util = getJdbcPool().borrowObject(); // 重要,即使后面兩句報錯,也能在finally中的endTransaction將連接還給連接池 utilThreadLocal.set(util); Connection connection = util.getConnection(); connection.setAutoCommit(false); } catch (Exception e) { throw new DBException("start transaction error"); } }
setAutoCommit(false)開啟事務,mysql默認rr,因此即使當中手動改了數據,由於rr,兩次打印一樣
2【只讀事務實踐】
work log 2020.4.28
只讀事務沒有報錯,但是確實沒有插入