spring的事务配置详解

2023-11-19

接下来我将给大家介绍spring事务配置的两种方式:

1.基于XML的事务配置。2.基于注解方式的事务配置。

前言:在我们详细介绍spring的两种声明式事务管理之前,我们需要先理解这些概念

1)spring的事务管理是通过Aop的方式来实现;
2)声明式事务是spring对事务管理的最常用的方式,因为这种方式对代码的影响最小,因此也就符合非侵入式的轻量级的容器的概念;
3)我们需要理解事务的概念,这里不再给出详细说明。

正文:

1.基于XMl的事务配置

现在假设我们有这样一个接口:
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);  
} 
</pre>对应于这个接口有一个实现类如下:<pre name="code" class="java">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();  
  }}  
注:上述两端代码是对应于业务层的。我们平时配置事务也最好在业务层进行配置。
接下来我们看一下spring 的配置文件中需要我们配置什么吧
<!-- from the file 'context.xml' -->  
<?xml version="1.0" encoding="UTF-8"?>  
<beans xmlns="http://www.springframework.org/schema/beans"  
     xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"  
     xmlns:aop="http://www.springframework.org/schema/aop"  
     xmlns:tx="http://www.springframework.org/schema/tx"  
     xsi:schemaLocation="  
     http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd  
     http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-2.5.xsd  
     http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-2.5.xsd">  
    
  <!-- 首先我们要把服务对象fooService声明成一个bean -->  
  <bean id="fooService" class="x.y.service.DefaultFooService"/>  
  
  <!-- 然后是声明一个事物建议tx:advice,spring为我们提供了事物的封装,这个就是封装在了<tx:advice/>中 -->
  <!-- <tx:advice/>有一个transaction-manager属性,我们可以用它来指定我们的事物由谁来管理。 -->
  <tx:advice id="txAdvice" transaction-manager="txManager">  
  <!-- 配置这个事务建议的属性 -->  
  <tx:attributes>  
    <!-- 指定所有get开头的方法执行在只读事务上下文中 -->  
    <tx:method name="get*" read-only="true"/>  
    <!-- 其余方法执行在默认的读写上下文中 -->  
    <tx:method name="*"/>  
  </tx:attributes>  
  </tx:advice>  
    
  <!-- 我们定义一个切面,它匹配FooService接口定义的所有操作 -->  
  <aop:config>  
	<!-- <aop:pointcut/>元素定义AspectJ的切面表示法,这里是表示x.y.service.FooService包下的任意方法。 -->
  <aop:pointcut id="fooServiceOperation" expression="execution(* x.y.service.FooService.*(..))"/>  
	<!-- 然后我们用一个通知器:<aop:advisor/>把这个切面和tx:advice绑定在一起,表示当这个切面:fooServiceOperation执行时tx:advice定义的通知逻辑将被执行 -->
  <aop:advisor advice-ref="txAdvice" pointcut-ref="fooServiceOperation"/>  
  </aop:config>  
    
  <!-- 数据元信息 -->  
  <bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close">  
  <property name="driverClassName" value="oracle.jdbc.driver.OracleDriver"/>  
  <property name="url" value="jdbc:oracle:thin:@rj-t42:1521:elvis"/>  
  <property name="username" value="scott"/>  
  <property name="password" value="tiger"/>  
  </bean>  
  
  <!-- 管理事务的类-->  
  <bean id="txManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">  
  <property name="dataSource" ref="dataSource"/>  
  </bean>   
  <!-- other <bean/> definitions here -->  
</beans>  
现在我通俗的把上面的配置讲解一下:
首先我们应该要把服务对象'fooService' 声明成一个bean我们要把一个服务对象('fooService' bean)做成事务性的。
我们就应该首先在声明一个事务管理的建议,用什么来管理,spring给我们提供了事务封装,这个就封装在了<tx:advice/>中,
这个事务建议给我们提供了一个transaction-manager属性,用他可以指定我们用谁来管理我们的事务。我们上边的例子用的
为一个指向 PlatformTransactionManager bean的名字(这里指 'txManager'), 该bean将会真正管理事务。上面用的事务
管理类是用的jdbc中提供的事务管理,当然这里也可以指定为hibernate管理。当然了,不管用那个类来管理我们的事务,都
不要忘记了提供我们的datasource属性,因为事务管理也需要这里面的信息。我们声明好事务建议,也指定好了具体用哪个
类来管理了,下面我们的任务就是要把我们定义好的这些利用AOP把我们的事务管理织入到我们的业务逻辑里面
<aop:config/> 的定义, 它确保由 'txAdvice'  bean定义的事务通知在应用中合适的点被执行。 
首先我们定义了 一个切面,它匹配 FooService 接口定义的所有操作, 
我们把该切面叫做 'fooServiceOperation'。<aop:pointcut/> 元素定义是AspectJ的切面表示法,
上述表示x.y.service.FooService包下的任意方法。然后我们用一个通知器(advisor)把这个切面与 'txAdvice' 绑定在一起,
 表示当 'fooServiceOperation' 执行时,'txAdvice' 定义的通知逻辑将被执行。大体流程就是这样的了。

<tx:advice/> 有关的设置

通过 <tx:advice/> 标签来指定不同的事务性设置。默认的 <tx:advice/> 设置如下:

事务传播设置是 REQUIRED

隔离级别是DEFAULT

事务是 读/

事务超时默认是依赖于事务系统的,或者事务超时没有被支持。

任何 RuntimeException 将触发事务回滚,但是任何 checked Exception 将不触发事务回滚

这些默认的设置当然也是可以被改变的。 <tx:advice/> 和 <tx:attributes/> 标签里的 <tx:method/> 各种属性设置总结如下:

Table 9.1. <tx:method/> 有关的设置

属性

是否需要?

默认值

描述

name


与事务属性关联的方法名。通配符(*)可以用来指定一批关联到相同的事务属性的方法。 如:'get*''handle*''on*Event'等等。

propagation

REQUIRED

事务传播行为

isolation

DEFAULT

事务隔离级别

timeout

-1

事务超时的时间(以秒为单位)

read-only

false

事务是否只读?

rollback-for


将被触发进行回滚的 Exception(s);以逗号分开。 如:'com.foo.MyBusinessException,ServletException'

no-rollback-for


不 被触发进行回滚的 Exception(s);以逗号分开。 如:'com.foo.MyBusinessException,ServletException'


下面我们具体来看一下事务的传播性的几个值:

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


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


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


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


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


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


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

到此为止基于XML的事务配置就算完成了。




使用 @Transactional


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

下面的例子很好地演示了 @Transactional 注解的易用性,随后解释其中的细节。先看看其中的类定义

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


当我们使用注解式声明事务时,在XML中只需要一句话就ok了

<?xml version="1.0" encoding="UTF-8"?>  
<beans xmlns="http://www.springframework.org/schema/beans"  
     xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"  
     xmlns:aop="http://www.springframework.org/schema/aop"  
     xmlns:tx="http://www.springframework.org/schema/tx"  
     xsi:schemaLocation="  
     http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd  
     http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-2.5.xsd  
     http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-2.5.xsd">  
    
  <bean id="fooService" class="x.y.service.DefaultFooService"/>  
   <tx:annotation-driven transaction-manager="txManager"/>  
   <bean id="txManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">  
   <property name="dataSource" ref="dataSource"/>  
  </bean>  
</beans>

我们知道 @Transactional 注解可以声明在类上,也可以声明在方法上。在大多数情况下,方法上的事务会首先执行

例如: 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  
         
    }  
}  


@Transactional 有关的设置


@Transactional 注解是用来指定接口、类或方法必须拥有事务语义的元数据。 如:当一个方法开始调用时就开启一个新的只读事务,并停止掉任何现存的事务”。 默认的 @Transactional 设置如下:

事务传播设置是 PROPAGATION_REQUIRED

事务隔离级别是 ISOLATION_DEFAULT

事务是 读/

事务超时默认是依赖于事务系统的,或者事务超时没有被支持。

任何 RuntimeException 将触发事务回滚,但是任何 checked Exception 将不触发事务回滚

这些默认的设置当然也是可以被改变的。 @Transactional 注解的各种属性设置总结如下:

 @Transactional 注解的属性

属性

类型

描述

propagation

枚举型:Propagation

可选的传播性设置

isolation

枚举型:Isolation

可选的隔离性级别(默认值:ISOLATION_DEFAULT

readOnly

布尔型

读写型事务 vs. 只读型事务

timeout

int型(以秒为单位)

事务超时

rollbackFor

一组 Class 类的实例,必须是Throwable 的子类

一组异常类,遇到时 必须 进行回滚。默认情况下checked exceptions不进行回滚,仅unchecked exceptions(即RuntimeException的子类)才进行事务回滚。

rollbackForClassname

一组 Class 类的名字,必须是Throwable的子类

一组异常类名,遇到时 必须 进行回滚

noRollbackFor

一组 Class 类的实例,必须是Throwable 的子类

一组异常类,遇到时 必须不 回滚。

noRollbackForClassname

一组 Class 类的名字,必须是Throwable 的子类

一组异常类,遇到时 必须不 回滚

     在写代码的时候,不可能对事务的名字有个很清晰的认识,这里的名字是指会在事务监视器(比如WebLogic的事务管理器)或者日志输出中显示的名字, 对于声明式的事务设置,事务名字总是全限定名+"."+事务通知的类的方法名。比如BusinessService类的handlePayment(..)方法启动了一个事务,事务的名称是:

com.foo.BusinessService.handlePayment








使用 @Transactional


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

下面的例子很好地演示了 @Transactional 注解的易用性,随后解释其中的细节。先看看其中的类定义

@Transactional 有关的设置


@Transactional 注解是用来指定接口、类或方法必须拥有事务语义的元数据。 如:当一个方法开始调用时就开启一个新的只读事务,并停止掉任何现存的事务”。 默认的 @Transactional 设置如下:

事务传播设置是 PROPAGATION_REQUIRED

事务隔离级别是 ISOLATION_DEFAULT

事务是 读/

事务超时默认是依赖于事务系统的,或者事务超时没有被支持。

任何 RuntimeException 将触发事务回滚,但是任何 checked Exception 将不触发事务回滚

这些默认的设置当然也是可以被改变的。 @Transactional 注解的各种属性设置总结如下:

 @Transactional 注解的属性

属性

类型

描述

propagation

枚举型:Propagation

可选的传播性设置

isolation

枚举型:Isolation

可选的隔离性级别(默认值:ISOLATION_DEFAULT

readOnly

布尔型

读写型事务 vs. 只读型事务

timeout

int型(以秒为单位)

事务超时

rollbackFor

一组 Class 类的实例,必须是Throwable 的子类

一组异常类,遇到时 必须 进行回滚。默认情况下checked exceptions不进行回滚,仅unchecked exceptions(即RuntimeException的子类)才进行事务回滚。

rollbackForClassname

一组 Class 类的名字,必须是Throwable的子类

一组异常类名,遇到时 必须 进行回滚

noRollbackFor

一组 Class 类的实例,必须是Throwable 的子类

一组异常类,遇到时 必须不 回滚。

noRollbackForClassname

一组 Class 类的名字,必须是Throwable 的子类

一组异常类,遇到时 必须不 回滚

     在写代码的时候,不可能对事务的名字有个很清晰的认识,这里的名字是指会在事务监视器(比如WebLogic的事务管理器)或者日志输出中显示的名字, 对于声明式的事务设置,事务名字总是全限定名+"."+事务通知的类的方法名。比如BusinessService类的handlePayment(..)方法启动了一个事务,事务的名称是:

com.foo.BusinessService.handlePayment

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

spring的事务配置详解 的相关文章

随机推荐

  • java中的双端队列deque使用以及部分原理

    转载自 https www cnblogs com denglh p 7911513 html package collections import java util Deque import java util LinkedList P
  • 对于金融机构而言,为什么选择私有化 IM 比企业微信、钉钉更好?

    一 金融机构数字化转型迈向规范有序 更成体系的新阶段 当前 新一轮信息技术革命浪潮拉开序幕 以人工智能 大数据 云计算等为代表的数字技术正在重构全球经济 不少企业也纷纷拥抱数字化浪潮 开展全方位的变革和升级 中国银保监会印发 关于银行业保险
  • char字符表

    图片来源于网上
  • 如何在 GitHub 上找到免费且实用的软件?

    GitHub 虽说是以程序员为主的社区 但是上面托管的项目类型却风格迥异 有认真科研型的 也有上班划水型的 有面向极客宅男的开发工具 也有给小白麻瓜使用的普通软件 本周写了几篇文章 大多都在介绍与技术相关的开发工具与技巧 今天稍微调整一下
  • 生成csv文件并下载

    在做项目中 我们做一个功能的时候 可能要把数据做导出或下载处理 下载成各种格式 下面提供了一种excel下载格式 csv 将得到的数据 经过处理生成csv文件 并激活下载到本地 代码如下
  • 云计算目前国内外发展现状是什么,云计算主要存在哪些问题?

    远在 云计算 的名次出现之前 我国相关科技人员便已对互联网的透明资源储备技术进行了多方面应用 而随着科技的不断进步 对于云计算的应用愈加频繁 政府部门对云计算的建设提供了经济基础与社会软环境的保障 并且在国家科研部门当中设立了专业的部门 直
  • Android 获取本地视频列表

    activity video list xml
  • 将二叉树转换成双向链表

    输入一棵二叉搜索树 将该二叉搜索树转换成一个排序的双向链表 要求不能创建任何新的节点 只能调整树中节点指针的指向 因为二叉搜索树每个节点都有两个指针 分别是指向其左子节点和右子节点 所以将该节点的左子节点变成双向链表中的左节点 将该节点的右
  • 【数据结构】详解栈的应用之表达式求值

    首先明白 前缀表达式 符号在前 如 3456 中缀表达式 符号在中间 如 3 4 5 6 后缀表达式 符号在最后 如34 5 6 后缀表达式不出现括号 中缀表达式转后缀表达式的方法 1 遇到数字 直接输出 添加到后缀表达式中 2 栈为空时
  • python 关联图谱_机器学习算法与Python实践 - 知识图谱

    机器学习 人工智能 知识图谱 可以为自己建立一个机器学习的知识图谱 并争取掌握每一个经典的机器学习理论和算法 简单地总结如下 1 回归算法 多元自适应回归样条 MultivariateAdaptive Regression Splines
  • gmtime与localtime的区别

    目录 gmtime函数 linux环境下 window环境下 localtime函数 gmtime函数 gmtime转换的时间是UTL时间 与北京时间相差了8个小时 如果你想要得到北京时间 不建议你将gmtime转换后的时间直接加上八个小时
  • 小游戏开发:使用 React 和 Redux Tool Kit 实现俄罗斯方块

    大家好 我是若川 我持续组织了近一年的源码共读活动 感兴趣的可以 点此扫码加我微信 lxchuan12 参与 每周大家一起学习200行左右的源码 共同进步 同时极力推荐订阅我写的 学习源码整体架构系列 包含20余篇源码文章 历史面试系列 另
  • 进制图像的莫拉尔距离图

    进制图像的莫拉尔距离图 莫拉尔距离图是一种计算图像中对象之间距离的方法 通常用于形态学分析和图像处理的应用中 它可以帮助我们量化图像中不同对象之间的距离 并用于图像分割 边缘检测等任务 本文将介绍如何使用C C 语言实现进制图像的莫拉尔距离
  • 区块链技术与应用实验报告(实验六)

    文章目录 区块链技术与应用实验报告 实验六 关于作者 作者介绍 一 实验目的 二 实验原理简介 三 实验环境 四 实验步骤 1 访问 bitaddress org 等待网页跳转完毕 2 生成两对地址和私钥 3 生成一对新的地址和私钥 4 访
  • 彻底搞懂Vue中的Mixin混入

    1 什么是Mixin 其实Mixin不是Vue专属的 可以说它是一种思想 通俗点讲就是混入 在很多开发框架中都实现了Mixin 混入 我们这里主要讲解的是Vue中的Mixin 大白话解释 将组件的公共逻辑或者配置提取出来 哪个组件需要用到时
  • JS中的声明提升

    变量声明提升 使用var关键字声明的变量 会在所有的代码执行之前被声明 如果声明变量时未使用var关键字 变量不会被提前声明 console log a 输出undefined var a 1 等同于 var a console log a
  • RabbitMQ下的生产消费者模式与订阅发布模式

    所谓模式 就是在某种场景下 一类问题及其解决方案的总结归纳 生产消费者模式与订阅发布模式是使用消息中间件时常用的两种模式 用于功能解耦和分布式系统间的消息通信 以下面两种场景为例 数据接入 假设有一个用户行为采集系统 负责从App端采集用户
  • protobuf C#编译

    protobuf C 编译 标签 protobufc 2016 08 30 23 22 342人阅读 评论 1 收藏 举报 分类 工作记录 2 版权声明 本文为博主原创文章 未经博主允许不得转载 1 下载protobuf代码 https g
  • GO语言篇之CGO

    GO语言篇之CGO 文章目录 GO语言篇之CGO 前言 C代码嵌入GO代码 C文件嵌入GO代码 缺点 前言 Go语言可以通过内置的CGO调用C语言接口 从而实现C语言代码的交互 CGO提供了一种将Go代码嵌入到C代码中 或者从Go代码中调用
  • spring的事务配置详解

    接下来我将给大家介绍spring事务配置的两种方式 1 基于XML的事务配置 2 基于注解方式的事务配置 前言 在我们详细介绍spring的两种声明式事务管理之前 我们需要先理解这些概念 1 spring的事务管理是通过Aop的方式来实现