事务隔离级别 脏读 spring 测试

来源:互联网 发布:乐视盒子有线网络设置 编辑:程序博客网 时间:2024/06/03 23:06


建立一个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

@Servicepublic 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最后一次查询,返回空


结论:与理论相符




(二)

@Servicepublic 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内,出现了未提交的数据



(三)

@Servicepublic 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并没有延长会话





原创粉丝点击