精华内容
下载资源
问答
  • 疑问,确实像往常一样在service上添加了注解@Transactional,为什么查询数据库时还是发现有数据不一致的情况,想想肯定是事务没起作用,出现异常的时候数据没有回滚。于是就对相关代码进行了一番测试,结果发现一下...

      spring @Transactional注解 事务不回滚的两个原因

    一是Service类内部方法调用

    二是try...catch异常,我们自定义的异常不是 RuntimeException

    1. Service类内部方法调用

    大概就是 Service 中有一个方法 A,会内部调用方法 B, 方法 A 没有事务管理,方法 B 采用了声明式事务,通过在方法上声明 Transactional 的注解来做事务管理。示例代码如下:

    复制代码

    @Service
    public class RabbitServiceImpl implements RabbitService {
     
      @Autowired
      private RabbitDao rabbitDao;
      @Autowired
      private TortoiseDao tortoiseDao;
     
      @Override
      public Rabbit methodA(String name){
        return methodB(name);
      }
     
      @Transactional(propagation = Propagation.REQUIRED)
      public boolean methodB(String name){
        rabbitDao.insertRabbit(name);
        tortoiseDao.insertTortoise(name);
        return true;
      }
     
    }
    

    单元测试代码如下:

    public class RabbitServiceImplTest {
     
      @Autowired
      private RabbitService rabbitService;
     
      // 事务未开启
      @Test
      public void testA(){
        rabbitService.methodA("rabbit");
      }
     
      // 事务开启
      @Test
      public void testB(){
        rabbitService.methodB("rabbit");
      }
    }

    复制代码

     

    从上一节中可以看到,声明式事务是通通过AOP动态代理实现的,这样会产生一个代理类来做事务管理,而目标类(service)本身是不能感知代理类的存在的。

    对于加了@Transactional注解的方法来说,在调用代理类的方法时,会先通过拦截器TransactionInterceptor开启事务,然后在调用目标类的方法,最后在调用结束后,TransactionInterceptor 会提交或回滚事务,大致流程如下图:

    总结,在方法 A 中调用方法 B,实际上是通过“this”的引用,也就是直接调用了目标类的方法,而非通过 Spring 上下文获得的代理类,所以事务是不会开启的。

     

    2. try...catch异常

    在一段业务逻辑中对数据库异常进行了处理,使用了try...catch子句捕获异常并throw了一个自定义异常,这种情况导致了事务未回滚,示例代码如下:

     

    @Transactional(propagation = Propagation.REQUIRED)
    public boolean methodB(String name) throws BizException {
      try {
        rabbitDao.insertRabbit(name);
        tortoiseDao.insertTortoise(name);
      } catch (Exception e) {
        throw new BizException(ReturnCode.EXCEPTION.code, ReturnCode.EXCEPTION.msg);
      }
      return true;
    }

     

    上面代码中的声明式事务在出现异常的时候,事务是不会回滚的。在代码中我虽然捕获了异常,但是同时我也抛出了异常,为什么事务未回滚呢?猜测是异常类型不对,于是开始查询原因,翻看了Spring的官方文档,找到了答案。下面是翻译自Spring官网:

    看完官方文档这节内容找到了问题的答案,原来是因为我们自定义的异常不是 RuntimeException。我的解决办法是,在注解@Transactional中添加 rollbackFor={BizException.class}。可能你会问我为什么不将自定义异常修改为继承RuntimeException,因为我需要BizException是一个checked 异常。

    展开全文
  •  由于工作需要,需要在spring中配置两个数据源,有一天突然发现@Transactional注解失效 环境框架:  springmvc+spring+spring jdbcTemplate 数据库:  Oracle数据库 解决方法: 百度获得三种可能原因及相应...

    问题描述:

      由于工作需要,需要在spring中配置两个数据源,有一天突然发现@Transactional注解失效

    环境框架:

      springmvc+spring+spring jdbcTemplate

    数据库:

      Oracle数据库

     

    解决方法:

    百度获得三种可能原因及相应解决方案:

    第一种 

    springmvc包扫描覆盖spring包扫描

    1 <!– 自动扫描的包名 –>    
    2 <context:component-scan base-package=“com.yxyj” >   
    3 </context:component-scan>  

    spring容器优先加载由ServletContextListener(对应applicationContext.xml)产生的父容器,而SpringMVC(对应mvc_dispatcher_servlet.xml)产生的是子容器。子容器Controller进行扫描装配时装配的@Service注解的实例是没有经过事务加强处理,即没有事务处理能力的Service,而父容器进行初始化的Service是保证事务的增强处理能力的。如果不在子容器中将Service exclude掉,此时得到的将是原样的无事务处理能力的Service。

    springmvc的配置文件里包扫描范围太大,应该将service排除在外

    1 <context:component-scan base-package=“com.will” >      
    2     <context:exclude-filter type=“annotation” expression=“org.springframework.stereotype.Service” />    
    3 </context:component-scan>

    第二种

    使用的mysql数据库,数据库引擎使用的不是InnoDB,只要切换成InnoDB就可以了

    1 alter table tablename type=InnoDb

    第三种

    注解加的方法权限修饰符不是public,@Transational失效,修改修饰符为public

     

    结果是,我的注解扫描范围只有controller层,所以第一种方案失败,数据库是Oracle数据库,第二种解决方案失败,方法权限修饰符就是public,第三种方案失败......

     

    接下来,继续查找原因,然后了解到原来事务是和数据源绑定的,如果不给事务管理器qualifer属性,@Transactional默认会与第一个事务管理器绑定,结果我用的是第二个数据源,导致Transactional失效

    解决方案:

    配置事务管理器时添加value区分字段

        <bean id="transactionManager02"
            class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
            <property name="dataSource" ref="dataSource02" />
            <qualifier value="ynw"></qualifier>
        </bean>

    java代码中添加value

    1 @Transactional(value = "ynw")
    2 public HashMap<String, Object> addAppointMent(Map map) {}

    这样事务就可以使用了

    转载于:https://www.cnblogs.com/cdream-zs/p/9515545.html

    展开全文
  • @Transactional事务注解失效篇(一)

    千次阅读 2019-08-14 17:08:25
    Spring中的@Transactional相信大家都已经用过不少,不知道大家有没有遇到过明明检查了三遍事务配置都是正确,但是它就是不生效,嘿,你说气不气!

    更多最新文章欢迎大家访问我的个人博客😄:豆腐别馆
      
    Spring中的@Transactional相信大家都已经用过不少,不知道大家有没有遇到过明明检查了三遍事务配置都是正确,但是它就是不生效,嘿,你说气不气。

    翻车现场

    1. 我们模拟一下用户注册成功后调用第三方网关发送短信提醒的这么一个过程,主要代码只有两个方法,一是用户新增,还有一个是短信发送。都在其方法上方加上@Transactional事务注解,接着为了防止由于第三方短信网关的不稳定从而导致影响到用户注册的主要流程,我们在调用短信的地方捕获下异常:
    /**
     * 用户服务
     * 转载请注明出处,更多技术文章欢迎大家访问我的个人博客站点:https://www.doufuplus.com
     *
     * @author 丶doufu
     * @date 2019/08/14
     */
    @Service
    public class UserServiceImpl implements UserService {
    
        private static final Log logger = LogFactory.getLog(UserServiceImpl.class);
    
        @Autowired
        private UserMapper userMapper;
    
        @Autowired
        private MsgMapper msgMapper;
    
        /**
         * 用户注册
         * 转载请注明出处,更多技术文章欢迎大家访问我的个人博客站点:https://www.doufuplus.com
         *
         * @author 丶doufu
         * @date 2019/08/14
         */
        @Override
        @Transactional
        public int register(User user) {
            // ...
            userMapper.insert(user);
            // sendMsg(user);
            try {
                sendMsg(user);
            } catch (Exception e) {
                logger.info(e.getMessage());
            }
            // ...
            return 0;
        }
    
        /**
         * 模拟调用短信网关发送短信
         * 转载请注明出处,更多技术文章欢迎大家访问我的个人博客站点:https://www.doufuplus.com
         *
         * @author 丶doufu
         * @date 2019/08/14
         */
        @Override
        @Transactional
        public void sendMsg(User user) {
            Msg msg = new Msg(user.getId(), "欢迎来到豆腐别馆", new Date());
            msgMapper.insert(msg);
    
            // 调用短信网关
            // ...
            throw new RuntimeException("调用短信网关失败!");
        }
    }
    
    
    1. 看一下测试用例:
    @RunWith(SpringRunner.class)
    @SpringBootTest(classes = WebApplication.class)
    public class TransactionDisableTest {
    
        @Autowired
        private UserService userService;
    
        @Test
        public void testTransactional() {
            User user = new User("doufuplus", "123456", new Date());
            userService.register(user);
        }
    }
    
    1. 我们可以猜测下代码的最终运行结果,sendMsg()方法由于加了@Transactional事务注解,且在方法内部已经抛出了RuntimeException,那么运行结果应该是:用户表成功插入数据,短信表由于发生异常产生回滚所以没有数据。只是事实真的是这样的吗?来看一看数据库:
      运行结果
      嗯哼?说好的要做彼此的天使,你却不管不顾插入了数据库~

    事故原因

    我们知道@Transactional是Spring基于aop机制实现的一个事务注解,而aop的本质实际上就是动态代理。在应用系统调用声明@Transactional 的目标方法时, aop动态代理会在代码运行时会生成一个代理对象(我们有时候在debug时看到的类似{$Proxy0}),再由这个代理对象来进行统一调用及增强。
    而当我们在Service直接调用内部方法时,其本质是通过this对象来调用的方法,即上文中的sendMsg(user);事实上等价于this.sendMsg(user);,这时候的调用,它已经绕开了sendMsg()的代理对象,因此也就做不了代理对象的相关增强,事务也就自然而然地失效了。

    解决办法

    1. (方法一)既然刚才的代码是通过this对象调用导致的失效,那么我们是不是也可以强制让它用回代理对象呢?当然是可以的,我们可以使用AopContext.currentProxy();获取当前类对象的动态代理进行显式调用:
    /**
      * 用户注册
      * 转载请注明出处,更多技术文章欢迎大家访问我的个人博客站点:https://www.doufuplus.com
      *
      * @author 丶doufu
      * @date 2019/08/14
      */
     @Override
     @Transactional
     public int register(User user) {
         // ...
         userMapper.insert(user);
         // sendMsg(user);
         try {
             UserService currentProxy = (UserService) AopContext.currentProxy();
             currentProxy.sendMsg(user);
         } catch (Exception e) {
             logger.info(e.getMessage());
         }
         // ...
         return 0;
     }
    

    如使用Spring框架,需在xml配置文件新增如下语句开启cglib代理,开启exposeProxy=true暴露代理对象:

    <aop: aspectj-autoproxy expose-proxy="true"/>

    1. (方法二)同样的,当然也可以将sendMsg()方法放置于不同的类来避免this调用问题。

    2. 看看运行结果,可以看到已经达到了我们的预期效果:
      解决效果

    后记

    事实上,此种情况不单单只是在使用@Transactional事务注解的情况下会失效,所有以aop实现的注解都是有可能失效的。比如@Async异步注解,比如一些我们自定义的aop注解等等。
    项目源码:GitHub (注意选择分支:transactional)

    展开全文
  • 工作中Springboot@Transaction事务注解失效问题问题解决方法 问题 在分享我工作中遇到的事务问题之前,先简单给大家分享一下Springboot事务失效的几种常见原因 1、检查数据库的引擎是否是innoDB 2、启动类上是否加入...

    工作中Springboot@Transaction事务注解失效问题

    问题

    在分享我工作中遇到的事务问题之前,先简单给大家分享一下Springboot事务失效的几种常见原因

    1、检查数据库的引擎是否是innoDB

    2、启动类上是否加入@EnableTransactionManagement注解(这个并不是必须的,springboot默认开启)

    3、是否在方法上加入@Transactional注解或Service的类上是否有@Transactional注解

    4、方法是否为public修饰的

    5、是否是因为抛出了Exception等Checked检查异常,默认情况下,spring会对unchecked异常进行事务回滚;如果是checked异常则不回滚。如果想回滚Excepton异常可以在注解上添加@Transactional(rollbackFor = Exception.class)这样添加就可以了

    6、在一个类中的方法调用时,被调用的方法如果有事务管理,那么事务管理会失效。

    7、是否添加了@Async异步注解

    8、事务方法的类是否被代理,可用AopUtils.isAopProxy()查看

    我的错误是在Spirngboot中整合shiro的时候在Realm自动装配了Service层导致事务的Service没有被代理,所以引起了事务失效。

    解决方法

    在Realm中自动装配的Service加上 @Lazy便可以解决了

    展开全文
  • MySql的MyISAM引擎不支持事务,导致事务注解失效。 2.没有被Spring管理 // @Service public class OrderServiceImpl implements OrderService { @Transactional public void updateOrder(Order order) { ...
  • Spring中事务失效@Transaction 注解失效的原理以及解决方案失效场景场景一失效原理解决方案场景二场景三 失效场景 场景一 1.在一个没有@transaction方法上调用另外一个有该注解的方法,那么另外一个方法的注解将会是...
  • Transactional注解标注方法修饰符为非public时,@Transactional注解将会不起作用。例如代码如下: 定义一个错误的@Transactional标注实现,修饰一个默认访问符的方法 @Component public class TestServiceImpl { @...
  • } } 事务注解实效 @Service public class TranService { @Transactional(rollbackFor = Exception.class) public void add() { //数据库操作........ //从线程中获取代理对象 TranService ...
  • 事务注解失效的六种场景 环境搭建 sql CREATE TABLE `student` ( `id` int(11) NOT NULL AUTO_INCREMENT COMMENT '主键', `name` varchar(255) DEFAULT NULL COMMENT '姓名', PRIMARY KEY (`id`) ) ENGINE=InnoDB...
  • 有时候在使用的过程中@Async注解失效(原因和@Transactional注解有时候会失效的原因一样)。 下面定义一个Service: 两个异步执行的方法test03()和test02()用来模拟项目中可能出现的耗时的操作,然后test()方法...
  • Spring事务注解Transactional失效

    万次阅读 2018-05-26 14:25:52
    前情提要:当Service接口实现类中存在内部方法调用,并且方法需要支持事务控制时,事务控制失效事务的传播级别为默认REQUIRED(默认模式)。1、简化版翻车代码:Service接口层Service接口实现类2、需求说明:(1)...
  • 点击关注公众号,Java干货及时送达作者:向北blog.csdn.net/qq_20597727/article/details/84900994Transactional失效场景介绍第一...
  • springBoot注解事务失效分析总结

    千次阅读 2019-10-23 11:03:15
    前段时间在项目中使用到spring事务注解功能,在自测代码时发现异常下未能产生回滚操作,借此空闲将之前问题定位思路整理如下,希望对大家定位该类问题提供解决思路。 二 分析与解决 本次测试工程采用springBoot+...
  • 上文《@Transactional事务注解失效篇(一)》中我们提到了在同个类下调用方法的事务失效情况,实际上使@Transactional事务注解失效的情况还有很多,这里我就不再重复造车轮,在网上看到篇写得挺不错的博文把我想说的...
  • 并没有实现事务,异常不会回滚,也就是说注解失效了。随后在网上查阅了部分资料,他打算显示的获取代理,然后再执行,这时却抛出 了空指针异常,这让他相当的困惑。 @Service @Slf4j public class A { @...
  • 显然并不是这样,我们使用@Transactional注解时需要注意许多的细节,不然你会发现@Transactional莫名其妙的就失效了。 @Transactional注解可以作用于哪些地方? 作用于类:当把@Transactional 注解放在类上时,...
  • springs事务注解失效

    2018-07-10 16:51:55
    关于spring 事务注解失效 情景: 非事务方法A,调用事务方法B,事务方法B失效 原因: spring的事务传递机制,导致B方法失效。 解决办法: 代理。cglib动态增强。 也可以直接在A方法上加事务,这样会降低效率。 ...
  • @Transactional注解标注方法修饰符为非public方法时,@Transactional注解将会不起作用。 例如以下代码,定义一个错误的@Transactional标注实现,修饰一个默认访问符的方法: @Service public class TestServiceImpl ...
  • 以上的访问方式,导致事务没开启,因此在方法抛出异常时,testMapper.insert(new Test(10,20,30));操作不会进行回滚。如果TestServiceImpl#insertTestWrongModifier方法改为public的话将会正常开启事务,testMapper....
  • 在一个@service方法上加上 @Transactional(rollbackFor = Exception.class)注解后,发现该方法中调用的另一个方法中抛出异常,在调用该方法之前的对表的修改未回滚,生效了。 问题代码: /** * @Description: 修改...
  • 引言 我们知道Spring自动装配会自动完成对象间依赖关系的注入,如果被注入的依赖使用了AOP,那么在依赖注入时,注入的是代理对象. ...调用者不是代理类,没法执行增强逻辑(注解对应的行为),导致注解失效. 举个开发中的例子
  • 在使用@Transactional注解时需要注意许多的细节,不然你会发现@Transactional总是莫名其妙的就失效了。首先呢,先简单介绍下Spring的事务:1、事务Spring提供了很好事务管理机制,主要分为编程式事务和声明式事务两...
  • 1.@Transactional 应用在非 public 修饰的方法上 ...这种失效是由于配置错误,若是错误的配置以下三种 propagation,事务将不会发生回滚。 TransactionDefinition.PROPAGATION_SUPPORTS:如果当前存在...
  • 类中的方法调用同一个类中的另一个方法时,注解失效; 如:@Cacheable,@Transactional 因为注解是通过代理类实现中,调用自身的方法当然不会生效。 你明白了吗? ...
  • 一、事务 二、@Transactional介绍 三、@Transactional失效场景 1、@Transactional 应用在非 public 修饰的方法上 2、@Transactional 注解属性 propagation 设置错误 3、@Transactional 注解属性 rollbackFor ...
  • //出现了检查异常,Transactional注解失效,但是可以解决 //设置一个检查异常 try { this.dao.out(outa, money); FileInputStream fin=new FileInputStream("a.txt");//检查异常 this....
  • 一直使用的都是注解式的事务@Transactional。完成开发自测时发现事务失效了。不科学啊,我写的代码怎么可能有bug!!项目事我滴搭建过好几个了,一直都是同一个套路,不可能有事务配置错误。于是乎分析了一下,把...
  • 1:注解失效场景 使用this调用了本类的方法 2:失效原因 没有通过代理对象调用方法,导致注解失效 3:解决方法 将方法挪到其他类中再调用(不推荐,改动太大) 从IOC获取对象,再调用方法 备注: 链接:获取IOC中...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 18,115
精华内容 7,246
关键字:

事务注解失效