资讯专栏INFORMATION COLUMN

spring事务处理

李文鹏 / 1623人阅读

摘要:声明式事务管理的事务管理是通过代理实现的。其中的事务通知由元数据目前基于或注解驱动。代理对象与事务元数据结合产生了一个代理,它使用一个实现品配合,在方法调用前后实施事务。

JDBC事务
1.获取连接 Connection con=DriverManager.getConnection();
2.开启事务 con.setAutoCommit(true/fase);
3.执行CRUD
4.提交事务或回滚事务 con.commit()/con.rollback()
5.关闭连接 con.close();
数据库隔离级别
隔离级别             隔离级别的值      导致的问题
Read-uncommitted       0            导致脏读;
Read-committed         1            避免脏读,允许不可重复读和幻读
Repeatable-Read        2            避免脏读、不可重复读,允许幻读
Serializable           3            全部避免

脏读:一事务对数据进行了修改,但未提交,另一事务可以读取到未提交的数据,如果第一个事务发生了回滚,那么第二事务就读到了。不可重复读:一个事务中发生了两次读操作,第一次读操作和第二次操作之间,另外一个事务对数据进行了修改,导致两次读的数据不一致。幻读:第一个事务对一定范围的数据进行批量修改,第二个事务在这个范围内增加一条数据,这时候第一个事务就会丢失对新数据的修改。
spring事务的传播性

事务传播性就定义在多个事务同时存在的时候,spring应该如何处理这些事务的行为,以事务嵌套为例,来深入理解spring事务传播的机制;
假设:外层事务servicea的methoda()调用内层service的methodb()若spring的级别为:propagation_required(spring的默认值)。如果serviceb.methodb()的事务级别定位为propagation_required,那么执行servicea.methoda()的时候,spring已经发起了事务,这时调用serviceb.methodb(),serviceb.methodb()看到自己已经运行在servicea.methoda()的事务内部,就不再起新的事务。假设serviceb.methodb()运行的时候发现自己没有在事务中,他就会为自己分配一个事务。这样,在servicea.methoda()或者serviceb.methodb()内的任何地方出现异常,事务都会被回滚。

全局事务和本地事务

所谓的全局事务也可以理解为分布式事务,也就是说程序需要处理来自不同的数据库连接;

所谓的本地事务可以理解为应用程序不需要处理分布式的数据库集群,只处理单一的数据源。

spring的关键抽象

spring事务抽象中的关键是,事务策略的概念,这个概念由org.springframework.transcation.PlatformTransactionManager接口定义。使用spring时,无论选择编程式事务管理,还是声明式事务管理,都必须定义一个正确的PlatformTransactionManager实现。举例如下所示:


    

通过创建事务管理器,就可将应用连接到不同的事务源上。

spring使用资源同步的事务

通过配置事务管理器,我们将应用连接到了不同的事务源上,接下来我们需要直接或间接地获取一种持久化api(jdbc等)的应用代码,来获取或操作资源以实现事务的同步。

spring提供了两种解决方案,一种是高层抽象的解决方案即对所有持久化API都采用这种 模板 方法,包括 JdbcTemplate、HibernateTemplate和JdoTemplate类,另外一种是低层的解决方案,有以下这些类:DataSourceUtils(针对JDBC),SessionFactoryUtils(针对Hibernate),PersistenceManagerFactoryUtils(针对JDO)等等。

当对应用代码来说,直接同原始持久化API特有的资源类型打交道是更好的选择时,这些类确保应用代码获取到正确的Spring框架所管理的bean,事务被正确同步,处理过程中的异常被映射到一致的API。

spring声明式事务管理

Spring的事务管理是通过AOP代理实现的。 其中的事务通知由元数据(目前基于XML或注解)驱动。 代理对象与事务元数据结合产生了一个AOP代理,它使用一个PlatformTransactionManager 实现品配合TransactionInterceptor,在方法调用前后实施事务。

举例说明:

    // 我们想做成事务性的服务接口

    package x.y.service;
    
    public interface FooService {
    
      Foo getFoo(String fooName);
    
      Foo getFoo(String fooName, String barName);
    
      void insertFoo(Foo foo);
    
      void updateFoo(Foo foo);
    
    }
    // 上述接口的一个实现

    package x.y.service;
    
    public class DefaultFooService implements FooService {
    
      public Foo getFoo(String fooName) {
        throw new UnsupportedOperationException();
      }
    
      public Foo getFoo(String fooName, String barName) {
        throw new UnsupportedOperationException();
      }
    
      public void insertFoo(Foo foo) {
        throw new UnsupportedOperationException();
      }
    
      public void updateFoo(Foo foo) {
        throw new UnsupportedOperationException();
      }
    
    }

我们假定,FooService的前两个方法(getFoo(String) 和getFoo(String, String))必须执行在只读事务上下文中,其他的方法(insertFoo(Foo)和 updateFoo(Foo))必须执行在可读写事务上下文中。定义配置文件如下:

   
   
   
  
  
  

  
  
  
  
    
    
    
    
  
  
  
  
  
  
  
  
  
  
  
  
  
  
  
  

  
  
  
   
  
  
  

分析一下上面的配置。我们要把一个服务对象("fooService" bean)做成事务性的。 施加的事务语义封装在定义中。 “把所有以 "get" 开头的方法看做执行在只读事务上下文中, 其余的方法执行在默认语义的事务上下文中”。 其中的 "transaction-manager" 属性被设置为一个指向 PlatformTransactionManager bean的名字(这里指 "txManager"),该bean将会真正管理事务。

配置中最后一段是 的定义, 它确保由 "txAdvice" bean定义的事务通知在应用中合适的点被执行。 首先我们定义了 一个切面,它匹配 FooService 接口定义的所有操作, 我们把该切面叫做 "fooServiceOperation"。然后我们用一个通知器(advisor)把这个切面与 "txAdvice" 绑定在一起, 表示当 "fooServiceOperation" 执行时,"txAdvice" 定义的通知逻辑将被执行。
元素定义是AspectJ的切面表示法.

上面的配置将为"fooService" bean创建一个代理对象,这个代理对象被装配了事务通知,所以当它的相应方法被调用时,一个事务将被启动、挂起、被标记为只读,或者其它(根据该方法所配置的事务语义)。

spring回滚

在Spring框架的事务架构里,当context的事务里的代码抛出 Exception 时事务进行回滚。Spring框架的事务基础架构代码将从调用的堆栈里捕获到任何未处理的 Exception,并将标识事务将回滚。然而,请注意Spring框架的事务基础架构代码将默认地只在抛出运行时和unchecked exceptions时才标识事务回滚。也就是说,当抛出一个 RuntimeException 或其子类例的实例时。(Errors 也一样 - 默认地 - 标识事务回滚。)从事务方法中抛出的Checked exceptions将不被标识进行事务回滚。

下面的XML配置片断里示范了如何配置一个用于回滚的checked、应用程序特定的 Exception 类型。


  
  
  
  

有时候你不想在异常抛出的时候回滚事务,就可以使用“不回滚规则”。 在下面的例子中,我们告诉Spring 框架即使遇到没有经过处理的InstrumentNotFoundException异常,也不要回滚事务。


  
  
  
  

当Spring框架捕获到一个异常后会检查配置回滚规则来决定是不是要回滚事务,这时候会遵循最匹配的规则。 所以在下面这种配置中,除了InstrumentNotFoundException这种类型的异常不会导致事务回滚以外,其他任何类型的异常都会。


  
  
  

第二种方法是通过 编程式 方式来指定回滚事务。 虽然写法非常的简单,但是这个方法是高侵入性的,并且使你的代码与Spring框架的事务架构高度耦合。 下面的代码片断里示范了Spring框架管理事务的编程式回滚:

public void resolvePosition() {
  try {
    // some business logic...
  } catch (NoProductInStockException ex) {
    // trigger rollback programmatically
    TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
  }
}

编程式方法的回滚对你来说是可见,如果你需要它你就可以使用,但是使用它就直接违反了在你的应用中使用一个纯基于POJO的模型。

@Transactional注解

除了基于XML文件的声明式事务配置外,你也可以采用基于注解式的事务配置方法。直接在Java源代码中声明事务语义的做法让事务声明和将受其影响的代码距离更近了,而且一般来说不会有不恰当的耦合的风险,因为,使用事务性的代码几乎总是被部署在事务环境中举例如下:

    @Transactional
    public class DefaultFooService implements FooService {
    
      Foo getFoo(String fooName);
    
      Foo getFoo(String fooName, String barName);
    
      void insertFoo(Foo foo);
    
      void updateFoo(Foo foo);
    }

当上述的POJO定义在Spring IoC容器里时,上述bean实例仅仅通过一 行xml配置就可以使它具有事务性的。如下:

    
    
    
      
      
      
    
      
      
    
      
      
      
         
      
      
      
    
    
    

@Transactional 注解可以被应用于接口定义和接口方法、类定义和类的 public 方法上。 然而,请注意只是使用 @Transactional 注解并不会启用事务行为, 它仅仅 是一种元数据,能够被可以识别 @Transactional 注解和上述的配置适当的具有事务行为的beans所使用。上面的例子中,其实正是 元素的出现 开启 了事务行为。

Spring团队的建议是你只在具体的类上使用 @Transactional 注解, 而不要注解在接口上。你当然可以在接口(或接口方法)上使用 @Transactional 注解, 但是这只有在你使用基于接口的代理时它才会生效。因为注解是 不能继承 的, 这就意味着如果你正在使用基于类的代理时,事务的设置将不能被基于类的代理所识别,而且对象也不会被事务代理所包装 (这是很糟糕的)。

元素上的"proxy-target-class" 属性 控制了有什么类型的事务性代理会为使用@Transactional 来注解的类创建代理。 如果"proxy-target-class" 属性被设为"true",那么基于类的代理就会被创建。 如果"proxy-target-class" 属性被设为"false" 或者没设,那么会创建基于接口的标准JDK代理。

在多数情形下,方法的事务设置将被优先执行。在下列情况下,例如: DefaultFooService 类在类的级别上被注解为只读事务,但是,这个类中的 updateFoo(Foo) 方法的 @Transactional 注解的事务设置将优先于类级别注解的事务设置。

@Transactional(readOnly = true)
public class DefaultFooService implements FooService {

  public Foo getFoo(String fooName) {
    // do something
  }

    // these settings have precedence for this method
    @Transactional(readOnly = false, propagation = Propagation.REQUIRES_NEW)
    public void updateFoo(Foo foo) {
        // do something
        
    }
}

    

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/70257.html

相关文章

  • 15个经典的Spring面试常见问题

    摘要:我自己总结的学习的系统知识点以及面试问题,已经开源,目前已经。目前最新的版本中模块的组件已经被废弃掉,同时增加了用于异步响应式处理的组件。每一次请求都会产生一个新的,该仅在当前内有效。显而易见,这种模式存在很多问题。 我自己总结的Java学习的系统知识点以及面试问题,已经开源,目前已经 41k+ Star。会一直完善下去,欢迎建议和指导,同时也欢迎Star: https://githu...

    sarva 评论0 收藏0
  • Spring Boot 参考指南(使用JTA分布式事务

    摘要:使用事务管理器是支持的一个流行的开源事务管理器实现,你可以使用启动器向项目添加适当的依赖项,与和一样,将自动配置并对进行后处理,以确保启动和关闭顺序是正确的。 37. 用JTA分布式事务 通过使用Atomikos或Bitronix嵌入式事务管理器,Spring Boot支持跨多个XA资源的分布式JTA事务,在部署到合适的Java EE应用服务器时也支持JTA事务。 当检测到JTA环境时...

    silenceboy 评论0 收藏0
  • 面试分享:最全Spring事务面试考点整理

    摘要:和事务的关系关系型数据库某些消息队列等产品或中间件称为事务性资源,因为它们本身支持事务,也能够处理事务。事务的传播特性,,,,,,强制要求要有一个物理事务。外围事务不会被内部事务的回滚状态影响。不支持当前事务。 Spring和事务的关系 关系型数据库、某些消息队列等产品或中间件称为事务性资源,因为它们本身支持事务,也能够处理事务。 Spring很显然不是事务性资源,但是它可...

    graf 评论0 收藏0
  • 基于Spring中的事务管理机制

    摘要:中的事务管理分类编程式事务管理机制声明式事务管理机制下面就银行转账这一实例来讲解如何利用这两种由提供的事务处理机制来进行相应的事务处理。 什么是事务? 通俗理解,事务其实就是一系列指令的集合。 为什么要使用事务管理? 我们在实际业务场景中,经常会遇到数据频繁修改读取的问题。在同一时刻,不同的业务逻辑对同一个表数据进行修改,这种冲突很可能造成数据不可挽回的错乱,所以我们需要用事务来对数据...

    SnaiLiu 评论0 收藏0

发表评论

0条评论

最新活动
阅读需要支付1元查看
<