只读事务与普通读
只读事务为了扩大事务的范围(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
只读事务没有报错,但是确实没有插入