4、Spring事务隔离级别
Spring面试之中隔离级别的面试问题是最为常见的,也是一个核心的基础所在,但是所谓的隔离级别一定要记住 , 是在并发环境
访问下才会存在的问题 。数据库是一个项目应用中的公共存储资源,所以在实际的项目开发过程中,很有可能会有两个不同的线程(每个线程拥有各自的数据库事务),要进行同一条数据的读取以及更新操作 。
文章插图
下面就通过代码的形式 一步步的揭开他的庐山真面目 。
- 对于事务,
private class BookRowMapper implements RowMapper<Book> {// 对象映射关系@Overridepublic Book mapRow(ResultSet rs, int rowNum) throws SQLException {Book book = new Book();book.setBid(rs.getInt(1));book.setTitle(rs.getString(2));book.setAuthor(rs.getString(3));book.setPrice(rs.getDouble(4));return book;}}@Testpublic void testInsertIsolation() throws InterruptedException { // 测试事务的隔离级别String query = "select bid,title,author,price from yootk.book where bid = ?"; // 查询String update = "update yootk.book set title = ?, author =? where bid =?"; // 根据id修改BookRowMapper bookRowMapper = new BookRowMapper(); // 对Book对象的映射DefaultTransactionDefinition definition =new DefaultTransactionDefinition(); // 创建默认事务对象Thread threadA = new Thread(() -> {TransactionStatus statusA = this.transactionManager.getTransaction(definition); //开始事务Book book = this.jdbcTemplate.queryForObject(query, bookRowMapper, 1); // 查询bid = 1的数据String name = Thread.currentThread().getName();// 获取线程名称System.out.println(11111 + "??????");LOGGER.info("{}【查询结果】:{}", name, book);try {TimeUnit.SECONDS.sleep(2); //等待两秒 让线程B修改之后再查询} catch (InterruptedException e) {throw new RuntimeException(e);}book = jdbcTemplate.queryForObject(query, bookRowMapper, 1); // 再次查询LOGGER.info("{}【查询结果】:{}", name, book);}, "事务线程-A");Thread threadB = new Thread(() -> {TransactionStatus statusB =transactionManager.getTransaction(definition); // 开启事务String name = Thread.currentThread().getName();// 获取线程名称int i = 0;try {i = jdbcTemplate.update(update, "Netty", "李老师", 1);LOGGER.info("{} 执行结果:{}", name, i);transactionManager.commit(statusB); // 提交事务} catch (DataAccessException e) {transactionManager.rollback(statusB); // 回滚事务throw new RuntimeException(e);}}, "事务线程-B");threadB.start();// 启动线程threadA.start();threadA.join();// 等待相互执行完成threadB.join();}
执行结果事务线程-A【查询结果】:Book(bid=1, title=Netty, author=李老师, price=99.9)事务线程-B 执行结果:1事务线程-A【查询结果】:Book(bid=1, title=Netty, author=李老师, price=99.9)
查看执行结果可知,我们线程B执行的是更新操作,但是更新成功后,在事务A进行查询时,本应是我们更新后的数据 , 这才对呀 。所以这个事务出现了事务不同步的问题 。4.1、脏读
为了保证并发状态下的数据读取的正确性,就需要通过事务的隔离级别来进行控制,实际上控制的就是脏读、幻读以及不可重复读的问题了 。
脏读(Dirty reads):事务A在读取数据时,读取到了事务B未提交的数据,由于事务B有可能被回滚,所以该数据有可能是一个无效数据
文章插图
4.2、不可重复读
不可重复读(Non-repeatable Reads):事务A对一个数据的两次读取返回了不同的数据内容,有可能在两次读取之间事务B对该数据进行了修改,一般此类操作出现在数据修改操作之中;
文章插图
4.3、幻读
幻读(Phantom Reads):事务A在进行数据两次查询时产生了不一致的结果 , 有可能是事务B在事务A第二次查询之前增加或删除了数据内容所造成的.
文章插图
Spring最大的优势是在于将所有的配置过程都进行了标准化的定义,于是在TransactionDefintion接口里面就提供了数据库隔离级别的定义常量 。
文章插图
从正常的设计角度来讲,在进行Spring事务控制的时候,不要轻易的去随意修改隔离级别(需要记住这几个隔离级别的概念),因为一般都使用默认的隔离级别 , 由数据库自己来实现的控制 。推荐阅读
- 空调漏氟的原因有哪些 五招轻松搞定空调漏氟问题
- 蚂蚁花呗怎么还款 三步就可以搞定
- 千元换屏100块搞定 苹果xr换外屏玻璃多少钱
- 怎样鉴别真假蜂蜜,几个方法搞定 怎样鉴别真假蜂蜜
- 醉驾找什么关系可搞定 醉驾找关系的最佳时间是什么时候
- 怎么样换备胎视频教程 如何换备胎教你这九步轻松搞定
- 六点识别真假驾照 驾驶证怎么辨别真假?6个窍门,3秒搞定!
- 科三靠边停车30公分操作技巧,四步搞定 科目三靠边停车30公分一把过技巧
- 科目三靠边停车30cm技巧,简单5步就搞定 科目三靠边停车30cm技巧
- 酒驾找什么关系可搞定 驾驶员酒驾找关系可以摆平