首页 > 其他分享 >幻读,重复读,脏读 以及Spring的事务属性说明

幻读,重复读,脏读 以及Spring的事务属性说明

时间:2023-08-10 20:32:06浏览次数:47  
标签:事务 读取 PROPAGATION 幻读 Spring 回滚 -- 脏读 READ


设置事务隔离性级别

    1)幻读:事务1读取记录时事务2增加了记录并提交,事务1再次读取时可以看到事务2新增的记录
    2)不可重复读取:事务1读取记录时,事务2更新了记录并提交,事务1再次读取时可以看到事务2修改后的记录
    3)脏读:事务1更新了记录,但没有提交,事务2读取了更新后的行,然后事务T1回滚,现在T2读取无效。    


    READ UNCOMMITTED:幻读,不可重复读和脏读均允许;
    READ COMMITTED:允许幻读和不可重复读,但不允许脏读;
    REPEATABLE READ:允许幻读,但不允许不可重复读和脏读;
    SERIALIZABLE:幻读,不可重复读和脏读都不允许

 

    ORACLE默认的是 READ COMMITTED     SET TRANSACTION ISOLATION LEVEL SERIALIZABLE|READ COMMITTED|READUNCOMMITTED|REPEATABLE READ;

 

spring 中一共定义了六种事务传播属性

    PROPAGATION_REQUIRED --支持当前事务,如果当前没有事务,就新建一个事务。这是最常见的选择。
 PROPAGATION_SUPPORTS -- 支持当前事务,如果当前没有事务,就以非事务方式执行。
 PROPAGATION_MANDATORY -- 支持当前事务,如果当前没有事务,就抛出异常。
 PROPAGATION_REQUIRES_NEW -- 新建事务,如果当前存在事务,把当前事务挂起。
 PROPAGATION_NOT_SUPPORTED -- 以非事务方式执行操作,如果当前存在事务,就把当前事务挂起。
 PROPAGATION_NEVER -- 以非事务方式执行,如果当前存在事务,则抛出异常。
 PROPAGATION_NESTED --如果当前存在事务,则在嵌套事务内执行。如果当前没有事务,则进行与PROPAGATION_REQUIRED类似的操作。

  前六个策略类似于EJBCMT,第七个(PROPAGATION_NESTED)是Spring所提供的一个特殊变量。
  它要求事务管理器或者使用JDBC 3.0 SavepointAPI提供嵌套事务行为(如Spring的DataSourceTransactionManager)

 

 

 

 

 

 

 

Spring @Transactional属性说明

 

 

 

Propagation

事务传播行为

PROPAGATION_REQUIRED--支持当前事务,如果当前没有事务,就新建一个事务。这是最常见的选择。

PROPAGATION_SUPPORTS--支持当前事务,如果当前没有事务,就以非事务方式执行。

PROPAGATION_MANDATORY--支持当前事务,如果当前没有事务,就抛出异常。

PROPAGATION_REQUIRES_NEW--新建事务,如果当前存在事务,把当前事务挂起。

PROPAGATION_NOT_SUPPORTED--以非事务方式执行操作,如果当前存在事务,就把当前事务挂起。

PROPAGATION_NEVER--以非事务方式执行,如果当前存在事务,则抛出异常。

PROPAGATION_NESTED--如果当前存在事务,则在嵌套事务内执行。如果当前没有事务,则进行与PROPAGATION_REQUIRED类似的操作。

Isolation

事务隔离级别

@Transactional(isolation = Isolation.READ_UNCOMMITTED)读取未提交数据(会出现脏读, 不可重复读) 基本不使用

@Transactional(isolation = Isolation.READ_COMMITTED)读取已提交数据(会出现不可重复读和幻读)

@Transactional(isolation = Isolation.REPEATABLE_READ)可重复读(会出现幻读)

@Transactional(isolation = Isolation.SERIALIZABLE)串行化

 

 

 

 

 

 

 

 

 

 

Spring事务的传播行为

 

在service类前加上@Transactional,声明这个service所有方法需要事务管理。每一个业务方法开始时都会打开一个事务。

Spring默认情况下会对运行期例外(RunTimeException)进行事务回滚。这个例外是unchecked

如果遇到checked意外就不回滚。

如何改变默认规则:

1 让checked例外也回滚:在整个方法前加上 @Transactional(rollbackFor=Exception.class)

2 让unchecked例外不回滚: @Transactional(notRollbackFor=RunTimeException.class)

3 不需要事务管理的(只查询的)方法:@Transactional(propagation=Propagation.NOT_SUPPORTED)

 

注意: 如果异常被try{}catch{}了,事务就不回滚了,如果想让事务回滚必须再往外抛try{}catch{throw Exception}。

 

spring——@Transactional事务不管理jdbc,所以要自己把jdbc事务回滚。



下面给出了回滚JDBC事务的代码示例:


Java代码

1. public void processT(String orders) {  
2. Context initCtx = new InitialContext();  
3. javax.sql.DataSource ds = javax.sql.DataSource)initCtx.lookup  
4. (“java:comp/env/jdbc/OrdersDB”);  
5. java.sql.Connection conn = ds.getConnection();  
6. try {  
7. conn.setAutoCommit( false ); //更改JDBC事务的默认提交方式  
8. orderNo = createOrder( orders );  
9. updateOrderStatus(orderNo, “orders created”);  
10. conn.commit(); //提交JDBC事务  
11. } catch ( Exception e ){  
12. try {  
13. conn.rollback(); //回滚sJDBC事务  
14. throw new EJBException(“事务回滚: “ + e.getMessage());  
15. } catch ( SQLException sqle ){  
16. throw new EJBException(“出现SQL操作错误: “ + sqle.getMessage());  
17. }  
18. }  
19. }



 

下面给出了JTA事务代码示例:



Java代码



    1. public void processOrder(String orderMessage) {  
    2. UserTransaction transaction = mySessionContext.getUserTransaction(); //获得JTA事务  
    3. try {  
    4. transaction.begin(); //开始JTA事务  
    5. orderNo = sendOrder(orderMessage);  
    6. updateOrderStatus(orderNo, “order sent”);  
    7. transaction.commit(); //提交JTA事务  
    8. } catch (Exception e){  
    9. try {  
    10. transaction.rollback(); //回滚JTA事务  
    11. } catch (SystemException se){  
    12. se.printStackTrace();  
    13. }  
    14. throw new EJBException(“事务回滚: “ + e.getMessage());  
    15. }  
    16. }


     

     

    在整个方法运行前就不会开启事务

           还可以加上:@Transactional(propagation=Propagation.NOT_SUPPORTED,readOnly=true),这样就做成一个只读事务,可以提高效率。

           各种属性的意义:

           REQUIRED:业务方法需要在一个容器里运行。如果方法运行时,已经处在一个事务中,那么加入到这个事务,否则自己新建一个新的事务。

           NOT_SUPPORTED:声明方法不需要事务。如果方法没有关联到一个事务,容器不会为他开启事务,如果方法在一个事务中被调用,该事务会被挂起,调用结束后,原先的事务会恢复执行。

           REQUIRESNEW:不管是否存在事务,该方法总汇为自己发起一个新的事务。如果方法已经运行在一个事务中,则原有事务挂起,新的事务被创建。

           MANDATORY:该方法只能在一个已经存在的事务中执行,业务方法不能发起自己的事务。如果在没有事务的环境下被调用,容器抛出例外。

           SUPPORTS:该方法在某个事务范围内被调用,则方法成为该事务的一部分。如果方法在该事务范围外被调用,该方法就在没有事务的环境下执行。

           NEVER:该方法绝对不能在事务范围内执行。如果在就抛例外。只有该方法没有关联到任何事务,才正常执行。

           NESTED:如果一个活动的事务存在,则运行在一个嵌套的事务中。如果没有活动事务,则按REQUIRED属性执行。它使用了一个单独的事务,这个事务 拥有多个可以回滚的保存点。内部事务的回滚不会对外部事务造成影响。它只对DataSourceTransactionManager事务管理器起效。

     

     

     

     

     

    Isolation Level(事务隔离等级)

    1、Serializable:最严格的级别,事务串行执行,资源消耗最大;
    2、REPEATABLE READ:保证了一个事务不会修改已经由另一个事务读取但未提交(回滚)的数据。避免了“脏读取”和“不可重复读取”的情况,但是带来了更多的性能损失。
    3、READ COMMITTED:大多数主流数据库的默认事务等级,保证了一个事务不会读到另一个并行事务已修改但未提交的数据,避免了“脏读取”。该级别适用于大多数系统。
    4、Read Uncommitted:保证了读取过程中不会读取到非法数据。隔离级别在于处理多事务的并发问题。
    我们知道并行可以提高数据库的吞吐量和效率,但是并不是所有的并发事务都可以并发运行。
    我们首先说并发中可能发生的3中不讨人喜欢的事情
    1: Dirty reads--读脏数据。也就是说,比如事务A的未提交(还依然缓存)的数据被事务B读走,如果事务A失败回滚,会导致事务B所读取的的数据是错误的。
    2: non-repeatable reads--数据不可重复读。比如事务A中两处读取数据-total-的值。在第一读的时候,total是100,然后事务B就把total的数据改成 200,事务A再读一次,结果就发现,total竟然就变成200了,造成事务A数据混乱。
    3: phantom reads--幻象读数据,这个和non-repeatable reads相似,也是同一个事务中多次读不一致的问题。但是non-repeatable reads的不一致是因为他所要取的数据集被改变了(比如total的数据),但是phantom reads所要读的数据的不一致却不是他所要读的数据集改变,而是他的条件数据集改变。比如Select account.id where account.name="ppgogo*",第一次读去了6个符合条件的id,第二次读取的时候,由于事务b把一个帐号的名字由"dd"改成"ppgogo1",结果取出来了7个数据。 

                                Dirty reads  non-repeatable reads phantom reads 
    Serializable                 不会             不会                        不会 
    REPEATABLE READ  不会             不会                        会 
    READ COMMITTED   不会              会                           会 
    Read Uncommitted    会                  会                           会 

    readOnly
    事务属性中的readOnly标志表示对应的事务应该被最优化为只读事务。


    标签:事务,读取,PROPAGATION,幻读,Spring,回滚,--,脏读,READ
    From: https://blog.51cto.com/u_6174294/7039819

    相关文章

    • Springboot 3.x 使用PageHelper实现MyBatis分页查询
      开发环境SpringBoot3.0.1Maven工程JDKOpenJdk17.0.6引入pom依赖<dependency><groupId>com.github.pagehelper</groupId><artifactId>pagehelper-spring-boot-starter</artifactId><version>1.4.7</version></depende......
    • 在Java中操作Redis_Spring Data Redis使用方式_环境搭建
          ......
    • 在Java中操作Redis_Spring Data Redis使用方式_操作步骤说明
          ......
    • SpringSecurity -- 授权-OAuth2 --
      前言针对之前的授权做个补充,这里集成OAuth2来实现目前支持5种方式,inMemory,jdbc,redis,jwt,jwk对于公司内部使用呢,主推jwt>redis>jdbc>inMemory​ 。。。jwk没玩明白,但是安全性挺高。。。整明白了,觉得可以主推!!!而认证类型呢,也有5种,authorization_code,refresh_token,password......
    • Springboot 测试@Test 工具
      别再用main方法测试了,太Low!这才是专业的SpringBoot项目测试方法!(qq.com)......
    • springboot quartz 定时任务
      定时任务实现方式quartz定时调用http请求quertz定时调用openfeginquartz定时调用普通定时任务springboot集成quartzpom.xml添加配置<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-quartz</artifactId>......
    • Spring Cloud Alibaba全解析:构建可靠的分布式系统
      标题:SpringCloudAlibaba全解析:构建可靠的分布式系统引言:随着互联网技术的不断发展,分布式系统的概念和应用越来越广泛。作为构建可靠和弹性的分布式系统的关键技术之一,SpringCloudAlibaba提供了一套完整的解决方案,帮助开发者更轻松地构建和管理分布式系统。本文将全面解析Spri......
    • SpringCloud实现大文件上传
      ​ 这里只写后端的代码,基本的思想就是,前端将文件分片,然后每次访问上传接口的时候,向后端传入参数:当前为第几块文件,和分片总数 下面直接贴代码吧,一些难懂的我大部分都加上注释了:上传文件实体类:看得出来,实体类中已经有很多我们需要的功能了,还有实用的属性。如MD5秒传的信息。......
    • 基于SpringBoot应⽤的logback⽇志配置
      SpringBoot默认整合了logback-classic⽇志框架,我们需要对logback⽇志框架进⾏配置以⾃定义⽇志输出格式、⽇志⽂件配置、⽇志⽂件保存策略等信息<?xmlversion="1.0"encoding="UTF-8"?><configuration><appendername="stdout"class="ch.qos.logback.core.ConsoleA......
    • springboot~alibaba.fastjson2序列化时过滤字段
      当我们使用阿里的alibaba.fastjson2进行json序列化时,你可以通过方法参数PropertyFilter来实现对字段的获取,将需要序列化的字段写到PropertyFilter对象里,当然也可以将不进行序列化的写到这里,进行逻辑非操作即可实体classPerson{privateStringfirstName;privateStr......