• 事务隔离级别 脏读 spring 测试


    建立一个controller,写两个url,用于测试脏读

    (一)

    TestController

        @Autowired
        private TestService testService;
    
        @RequestMapping(value = "listForDirtyRead", method = RequestMethod.GET)
        @ResponseBody
        @ApiImplicitParams({})
        @ApiOperation(value="listForDirtyRead")
        public Object index() {
    
            return testService.listForDirtyRead();
        }
    
    
        @RequestMapping(value = "insertForDirtyReadAndIllusion", method = RequestMethod.POST)
        @ResponseBody
        @ApiImplicitParams({})
        @ApiOperation(value="insertForDirtyReadAndIllusion")
        public void insertForDirtyReadAndIllusion() {
    
             testService.insertForDirtyReadAndIllusion();
        }

    TestService

    @Service
    public class TestService {
    
        @Autowired
        private JdbcTemplate jdbcTemplate;
    
        @Transactional(isolation = Isolation.READ_COMMITTED)
        public List<Map<String,Object>> listForDirtyRead() {
            List<Map<String,Object>> map = jdbcTemplate.queryForList("select * from tao");
            return map;
        }
    
        @Transactional
        public void insertForDirtyReadAndIllusion () {
            jdbcTemplate.execute("insert into tao values (1,'d')");
            try {
                Thread.sleep(10000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            int a = 1/0;
        }
    
    }

    注意:

    (1)此时insert函数也启用事务,意味着整个函数一起提交会话

    (2)list函数启用read_committed级别,理论上可以防脏读

    会话1执行insertForDirtyReadAndIllusion

    会话1睡眠阻塞

    会话2在10s内反复执行listForDirtyRead,始终返回空

    会话1返回,插入回滚

    会话2最后一次查询,返回空

    结论:与理论相符

    (二)

    @Service
    public class TestService {
    
        @Autowired
        private JdbcTemplate jdbcTemplate;
    
        @Transactional(isolation = Isolation.READ_UNCOMMITTED)
        public List<Map<String,Object>> listForDirtyRead() {
            List<Map<String,Object>> map = jdbcTemplate.queryForList("select * from tao");
            return map;
        }
    
        @Transactional
        public void insertForDirtyReadAndIllusion () {
            jdbcTemplate.execute("insert into tao values (1,'d')");
            try {
                Thread.sleep(10000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            int a = 1/0;
        }
    
    }
    


    注意:

    (1)这边一个小改动,将list隔离级别定义为 read_uncommitted,理论上无法防脏读

    (2)insert保留为事务,一个函数为一个会话一起commit,意味着在sleep的过程中,理论上会有脏读

    会话1执行insertForDirtyReadAndIllusion

    会话1睡眠阻塞

    会话2在10s内反复执行listForDirtyRead,始终返回

    [ { "col1":1, "col2":"d" }]

    会话1返回,插入回滚

    会话2最后一次查询,返回空

    结论:与理论相符,在事务insert阻塞的10s内,出现了未提交的数据

    (三)

    @Service
    public class TestService {
    
        @Autowired
        private JdbcTemplate jdbcTemplate;
    
        @Transactional(isolation = Isolation.READ_COMMITTED)
        public List<Map<String,Object>> listForDirtyRead() {
            List<Map<String,Object>> map = jdbcTemplate.queryForList("select * from tao");
            return map;
        }
    
    
        public void insertForDirtyReadAndIllusion () {
            jdbcTemplate.execute("insert into tao values (1,'d')");
            try {
                Thread.sleep(10000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            int a = 1/0;
        }
    
    }



    注意:

    (0)本案例考察service层不加事务标签时,jdbc的会话情况

    事务情况下:jdbc  遵循  setautocommit(false)   ...   try commit catch rollback  

    非事务情况下:mysql 默认自动提交

    (1)insert函数改为非事务,意味着一句sql即为一次会话,理论上我们无法在sleep过程中去再现脏读

    (2)list函数改为  read_commited,为避免脏读创造条件,假设insert事务在sleep时未提交,理论上则不应出现脏读

    会话1执行insertForDirtyReadAndIllusion

    会话1睡眠阻塞

    会话2在10s内反复执行listForDirtyRead,始终返回

    [ { "col1":1, "col2":"d" }]

    证明sql已经作为一个会话提交,sleep并未产生延迟放大会话的作用

    会话1返回,插入未回滚

    会话2最后一次查询,返回

    [ { "col1":1, "col2":"d" }]

    结论:与理论相符,sql作为单独一次会话提交,在sleep时,会话2查询即使在防脏读级别下也读到了“脏读”(实际不算脏读,是sql单次会话提交的数据)



     
     
     
    总结:
    (一)

                             修改方            查询方

    thread                   A                     B

    transcation          on               on(仅为了定义隔离级别,无关是否定义为一次会话)                             

    isolation           not care       read-commited

    无脏读

     

    (二)

                             修改方            查询方

    thread                   A                     B

    transcation          on               on(仅为了定义隔离级别,无关是否定义为一次会话)                             

    isolation           not care       read-uncommited

    有脏读

    (三)

                             修改方            查询方

    thread                   A                     B

    transcation          off               on(仅为了定义隔离级别,无关是否定义为一次会话)                             

    isolation           not care       read-commited

    在防脏读read-commited情况下读到了数据,反证了no transaction的会话为sql单独一次会话,sql后的sleep并没有延长会话



  • 相关阅读:
    Linux系统挂载NTFS移动硬盘
    ActiveReport报表开发谈谈ActiveReport的中文化问题
    硬件接口开发之USB电话录音盒来电显示
    如何使用正则表达式进行QQ校友的数据采集
    硬件接口开发之Modem来电显示
    关于MSHTML控件使用的问题
    【转】ISession接口介绍
    发送带嵌入图片邮件之SMTP实现和ESMTP实现
    C#进行MapX二次开发之地图搜索
    Database2Sharp混淆处理之经验分享(国庆专辑,祝福我们的祖国)
  • 原文地址:https://www.cnblogs.com/silyvin/p/9106779.html
Copyright © 2020-2023  润新知