spring事务回滚的多种方式「建议收藏」

spring事务回滚的多种方式「建议收藏」转:https://www.cnblogs.com/zeng1994/p/8257763.htmlstart看下下面的说明,会对理解本人贴出的代码有帮助。1.代码中事务控制的3种方式编程式事务:就是直接在代码里手动开启事务,手动提交,手动回滚。优点就是可以灵活控制,缺点就是太麻烦了,太多重复的代码了。声明式事务:就是使用SpringAop配置事务,这种方式大大的简化了编码。需要注…

大家好,又见面了,我是你们的朋友全栈君。如果您正在找激活码,请点击查看最新教程,关注关注公众号 “全栈程序员社区” 获取激活教程,可能之前旧版本教程已经失效.最新Idea2022.1教程亲测有效,一键激活。

Jetbrains全系列IDE稳定放心使用

转:https://www.cnblogs.com/zeng1994/p/8257763.html

start 看下下面的说明,会对理解本人贴出的代码有帮助。

1.代码中事务控制的3种方式

编程式事务:就是直接在代码里手动开启事务,手动提交,手动回滚。优点就是可以灵活控制,缺点就是太麻烦了,太多重复的代码了。声明式事务:就是使用SpringAop配置事务,这种方式大大的简化了编码。需要注意的是切入点表达式一定要写正确。
注解事务:直接在Service层的方法上面加上@Transactional注解,个人比较喜欢用这种方式。
2.事务不回滚的原因
    在工作中,看过别人写的代码出现了事务不回滚的现象。当然,事务不回滚的都是采用的声明式事务或者是注解事务;编程式事务都是自己写代码手动回滚的,因此是不会出现不回滚的现象。
    再说下声明式事务和注解事务回滚的原理:当被切面切中或者是加了注解的方法中抛出了RuntimeException异常时,Spring会进行事务回滚。默认情况下是捕获到方法的RuntimeException异常,也就是说抛出只要属于运行时的异常(即RuntimeException及其子类)都能回滚;但当抛出一个不属于运行时异常时,事务是不会回滚的。
    下面说说我经常见到的3种事务不回滚的产生原因:
(1)声明式事务配置切入点表达式写错了,没切中Service中的方法
(2)Service方法中,把异常给try catch了,但catch里面只是打印了异常信息,没有手动抛出RuntimeException异常
(3)Service方法中,抛出的异常不属于运行时异常(如IO异常),因为Spring默认情况下是捕获到运行时异常就回滚
3.如何保证事务回滚
    正常情况下,按照正确的编码是不会出现事务回滚失败的。下面说几点保证事务能回滚的方法
(1)如果采用编程式事务,一定要确保切入点表达式书写正确
(2)如果Service层会抛出不属于运行时异常也要能回滚,那么可以将Spring默认的回滚时的异常修改为Exception,这样就可以保证碰到什么异常都可以回滚。具体的设置方式也说下:
                        ① 声明式事务,在配置里面添加一个rollback-for,代码如下
 <tx:method name=”update*” propagation=”REQUIRED” rollback-for=”java.lang.Exception”/>
                        ② 注解事务,直接在注解上面指定,代码如下
@Transactional(rollbackFor=Exception.class)
(3)只有非只读事务才能回滚的,只读事务是不会回滚的
(4)如果在Service层用了try catch,在catch里面再抛出一个 RuntimeException异常,这样出了异常才会回滚
(5)如果你不喜欢(4)的方式,你还可以直接在catch后面写一句回滚代码(TransactionAspectSupport.currentTransactionStatus().setRollbackOnly(); )来实现回滚,这样的话,就可以在抛异常后也能return 返回值;比较适合需要拿到Service层的返回值的场景。具体的用法可以参见考下面的伪代码

/** TransactionAspectSupport手动回滚事务:*/
       @Transactional(rollbackFor = { Exception.class })  
       public boolean test() {  
            try {  
               doDbSomeThing();    
            } catch (Exception e) {  
                 e.printStackTrace();     
             //就是这一句了, 加上之后抛了异常就能回滚(有这句代码就不需要再手动抛出运行时异常了)
                 TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();  
                 return false;
            }  
         return true;
}

转 end

代码:

方式一、声明式事务

 1.在配置数据源的 application.xml中加入(加的时候注意头部是否有引入相应的xmlns命名空间):

  <!-- 方式一  声明式事务        begin -->
<!-- (事务管理)transaction manager, use JtaTransactionManager for global tx --> 
<!-- 配置JDBC数据源的局部数据管理器,使用DataSourceTransactionManager类 --> 
    <bean id="txManagerCommon"  
        class="org.springframework.jdbc.datasource.DataSourceTransactionManager">  
        <property name="dataSource" ref="dataSource" />  
    </bean> 
    <!-- 公共数据源注解拦截界面 -->
<tx:advice id="txAdviceCommon" transaction-manager="txManagerCommon">
<tx:attributes>
<tx:method name="*" 
rollback-for="java.lang.Exception" />
</tx:attributes>
</tx:advice>
<!-- 公共数据源 AOP拦截器设置 -->
<aop:config proxy-target-class="true">
<aop:advisor order="1"
pointcut="execution(* com.user.service.UserService.*(..))"  //aop 切入点
advice-ref="txAdviceCommon" /><!-- 切入点  -->
</aop:config>

<!– 事务        end –>  

配置完这个就可以对UserService中方法进行管理。

2.controller 代码

 /*事务回滚 新增两个用户信息*/
    @RequestMapping("/transaction") //url  
    public @ResponseBody
    String transaction( Model model){  
      String flag="0";
      try {
         flag=userService.transaction(); 
      } catch (Exception e) {
        flag="0";
      }
     return flag;
   } 

3.service代码

public String transaction() {
String flag="0";
String aString=null;
try {
  User user=new User();user1.setName("krystal222");user1.setPsd("222");
  insertUser(user);
  //异常回滚 beginaString.equals("aa");//异常回滚end
  User user1=new User();user1.setName("krystal222");user1.setPsd("222");
  insertUser(user1);
  flag="1";
 } 
 catch (Exception e) {
   flag="0";
   1//throw new NullPointerException("失败");//抛出一个 RuntimeException异常,这样出了异常才会 
  回滚
   2TransactionAspectSupport.currentTransactionStatus().setRollbackOnly(); //手动回滚
    二选一都可以实现(注意try catch 只是捕获异常,spring 事务默认只 
   有发生runtimeexception并且抛出这个异常时候才会回滚,2为手动回滚,算个例外吧)
 }
 return flag;
}

 

方式二、注解事务

spring中的@Transactional 放在类级别 和 方法级别 上一样效果

@Service
@Transactional

public class UserService {

@Transactional(rollbackFor = Exception.class, readOnly = false) 此处注释 上面戒了@Transactional
public String transaction() {
  
  

 1.在配置数据源的 application.xml中加入:

<!-- 方式一   注解 事务        begin -->



<!-- (事务管理)transaction manager, use JtaTransactionManager for global tx --> 
<!-- 配置JDBC数据源的局部数据管理器,使用DataSourceTransactionManager类 --> 
     <bean id="txManagerCommon"  
        class="org.springframework.jdbc.datasource.DataSourceTransactionManager">  
        <property name="dataSource" ref="dataSource" />  
    </bean> 
    <!-- 公共数据源使用注解定义事务 -->
<tx:annotation-driven transaction-manager="txManagerCommon" />

 

<!– 事务        end –>

2.controller

 /*事务回滚 新增两个用户信息*/
  @RequestMapping("/transaction") //url  
    public @ResponseBody
    String transaction( Model model){  
      String flag="0";
      try {
      flag=userService.transaction();
 
  } catch (Exception e) {
flag="0";
  }
     return flag;
   } 

3.service

@Transactional(rollbackFor = Exception.class, readOnly = false)
public String transaction() {
String flag="0";
String aString=null;
try {
User user=new User();user.setName("krystal111");user.setPsd("111");
insertUser(user);
//异常回滚 beginaString.equals("aa");//异常回滚end
User user1=new User();user1.setName("krystal222");user1.setPsd("222");
insertUser(user1);
flag="1";
} catch (Exception e) {
flag="0";
throw new NullPointerException("shibai");
//TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
}
return flag;

}

方式一方式二也可以共存,都在application.xml中配置

 

 说到这里,已经有了对 <tx:annotation-driven/> 的简单理解,那我们是否就可以在程序中所有被spring管理的类上都可以使用@Transactional注解了呢,在Service上可以使用@Transactional 注解这个是肯定的了,那总有些人也想弄明白能否在Controller 使用?答案显然是“不一定”的(与时间配置有关),下面做下解释:

在 spring-framework-reference.pdf 文档上有这样一段话:

<tx:annotation-driven/> only looks for @Transactional on beans in the same application context it is defined in. This means that, if you put <tx:annotation-driven/> in a WebApplicationContext for a DispatcherServlet, it only checks for @Transactional beans in your controllers, and not your services. 

意思就是:<tx:annoation-driven/>只会查找和它在相同的应用上下文件中定义的bean上面的@Transactional注解,如果你把它放在Dispatcher的应用上下文中,它只检查控制器(Controller)上的@Transactional注解,而不是你services上的@Transactional注解。

    所以,可以确定的是我们是可以在Controller上使用事务注解的,但是我们不推荐这样做(本人也从来没有这样做过),这里只是为了说明spring对<tx:annotation-driven/>的使用。

 

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。

发布者:全栈程序员-用户IM,转载请注明出处:https://javaforall.cn/180120.html原文链接:https://javaforall.cn

【正版授权,激活自己账号】: Jetbrains全家桶Ide使用,1年售后保障,每天仅需1毛

【官方授权 正版激活】: 官方授权 正版激活 支持Jetbrains家族下所有IDE 使用个人JB账号...

(0)


相关推荐

  • Android名词解释_古代汉语名词解释汇总

    Android名词解释_古代汉语名词解释汇总什么叫刷机刷机,是手机方面的专业术语,是指通过一定的方法更改或替换了手机原版系统中固有的一些语言、图片、铃声和软件版本或者操作系统,可以使手机功能更加完善。刷机可以是官方的,也可以是非官方的。再简单点说,刷机就是一种改变你手机操作系统的一种行为,就相当于给电脑装上不同版本的windows或则电脑重装系统,也就是刷手机的操作系统吧。目前常说的刷机就是用“更改替换了一些图片、铃声或菜单后的软件

    2022年10月10日
  • 汉诺塔递归太难理解了_函数定义时可以用递归吗

    汉诺塔递归太难理解了_函数定义时可以用递归吗记得我第一次做汉诺塔这道题时,是2017年11月。当时,我坐在山大青岛校区图书馆3楼,不知怎么地,看到了这个题。然后,就思考了一整天,233当然,悲剧就是,我当时花了一天的时间还是没有真正理解这道题递归的思路。如今,我终于懂了,嘿嘿嘿。关于递归:一定不要试图跟踪大型递归的过程!要写出递归,关键就是找出递归的递归方程式:也就是说,要完成最后一步,那么最后一步的前一步要做什…

    2022年10月25日
  • js删除数组中指定的元素_java数组删除元素

    js删除数组中指定的元素_java数组删除元素要删除数组中的指定的元素,当然肯定少不了遍历,肯定得匹配指定的index,然后用数组的splice()方法来实现,因为pop()从数组尾部删除元素,shift()从数组头部删除第一个元素,还有delete(),当然,splice()方法可以删除数组中任意位置的元素。splice(index,number);index:表示从第几个元素开始;number:表示从此元素开始,向后删除…

  • 基于qt的简单小游戏_中国象棋单机版2,0

    基于qt的简单小游戏_中国象棋单机版2,0最近对Qt这个跨平台C++图形应用程序框架很感兴趣,闲暇时间多学了一下,收获很多,也踩了不少坑,在这里记录一下,分享心得。Qt的安装安装Qt并不麻烦,就是网速有点慢。推荐使用国内镜像代理下载。首先进入Qt官网,在TryQt处点击DownloadQt,填完基本信息后,点击提交就可以下载Qt下载器了。当然,你也可以直接去国内镜像站上下载Qt下载器。打开Qt下载器,注册Qt账户,并登录,同意协议。若要使用国内镜像代理,点击左下角的配置图标。然后从百度上选择

  • python从入门到精通——完整教程

    python从入门到精通——完整教程<linkrel=”stylesheet”href=”https://csdnimg.cn/release/blogv2/dist/mdeditor/css/editerView/ck_htmledit_views-1a85854398.css”><divid=”content_views”class=”htmledit_views”><p>&nbsp;</p>文章目录…

  • Linux操作系统基础(完结)

    Linux操作系统基础(完结)一、Linux操作系统概述二、Linux操作系统安装三、Linux文件系统及文件基础四、Linux操作系统命令使用基础五、Linux应用程序的安装与卸载基础五、用户及进程六、相关信息查询七、网络配置八、Linux应用程序的安装与卸载基础九、vim

发表回复

您的电子邮箱地址不会被公开。

关注全栈程序员社区公众号