只读事务与普通读

只读事务为了扩大事务的范围(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

一种mysql jvm死锁

 

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

只读事务没有报错,但是确实没有插入

 

posted on 2020-04-08 00:09  silyvin  阅读(1232)  评论(0编辑  收藏  举报