面试官:spring事务失效有几个原因? 9个!解释一下?我傻了!

1.spring事务实现方式及原理

Spring 事务的本质其实就是数据库对事务的支持,没有数据库的事务支持,spring 是无法提供事务功能的。真正的数据库层的事务提交和回滚是在binlog提交之后进行提交的 通过 redo log 来重做, undo log来回滚。

一般我们在程序里面使用的都是在方法上面加@Transactional 注解,这种属于声明式事务。

声明式事务本质是通过 AOP 功能,对方法前后进行拦截,将事务处理的功能编织到拦截的方法中,也就是在目标方法开始之前加入一个事务,在执行完目标方法之后根据执行情况提交或者回滚事务。

记得点赞收藏加关注哦 ,需要下载PDF版本和更多知识点、面试题的朋友

可以加q群:799215493   备注:简书   免费领取~

2.数据库本身不支持事务

这里以 MySQL 为例,其 MyISAM 引擎是不支持事务操作的,InnoDB 才是支持事务的引擎,一般要支持事务都会使用 InnoDB

3.当前类的调用

@Service

public class UserServiceImpl implements UserService {

    public void update(User user) {

        updateUser(user);

    }


    @Transactional(rollbackFor = Exception.class)

    public void updateUser(User user) {

        // update user

    }


}

上面的这种情况下是不会有事务管理操作的。

通过看声明式事务的原理可知,spring使用的是AOP切面的方式,本质上使用的是动态代理来达到事务管理的目的,当前类调用的方法上面加@Transactional 这个是没有任何作用的,因为调用这个方法的是this.

OK, 我们在看下面的一种例子。

@Service

public class UserServiceImpl implements UserService {

    @Transactional(rollbackFor = Exception.class)

    public void update(User user) {

        updateUser(user);

    }


    @Transactional(propagation = Propagation.REQUIRES_NEW)

    public void updateUser(User user) {

        // update user

    }


}


这次在 update 方法上加了 @Transactional,updateUser 加了 REQUIRES_NEW 新开启一个事务,那么新开的事务管用么?

答案是:不管用!

因为它们发生了自身调用,就调该类自己的方法,而没有经过 Spring 的代理类,默认只有在外部调用事务才会生效,这也是老生常谈的经典问题了。

4.方法不是public的

@Service

public class UserServiceImpl implements UserService {

    @Transactional(rollbackFor = Exception.class)

    private void updateUser(User user) {

        // update user

    }


}

private 方法是不会被spring代理的,因此是不会有事务产生的,这种做法是无效的。

5.没有被spring管理

//@Service

public class UserServiceImpl implements UserService {

    @Transactional(rollbackFor = Exception.class)

    public void updateUser(User user) {

        // update user

    }


}

没有被spring管理的bean, spring连代理对象都无法生成,当然无效咯。

6.配置的事务传播性有问题

@Service

public class UserServiceImpl implements UserService {

    @Transactional(propagation = Propagation.NOT_SUPPORTED)

    public void update(User user) {

        // update user

    }   

}

回顾一下spring的事务传播行为

Spring 事务的传播行为说的是,当多个事务同时存在的时候, Spring 如何处理这些事务的行为。

PROPAGATION_REQUIRED:如果当前没有事务,就创建一个新事务,如果当前存在事务,就加入该事务,该设置是最常用的设置。

PROPAGATION_SUPPORTS:支持当前事务,如果当前存在事务,就加入该事务,如果当前不存在事务,就以非事务执行

PROPAGATION_MANDATORY:支持当前事务,如果当前存在事务,就加入该事务,如果当前不存在事务,就抛出异常。

PROPAGATION_REQUIRES_NEW:创建新事务,无论当前存不存在事务,都创建新事务。

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

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

PROPAGATION_NESTED:如果当前存在事务,则在嵌套事务内执行。如果当前没有事务,则按 REQUIRED 属性执行

当传播行为设置了PROPAGATION_NOT_SUPPORTED,PROPAGATION_NEVER,PROPAGATION_SUPPORTS这三种时,就有可能存在事务不生效

7.异常被你 "抓住"了

@Service

public class UserServiceImpl implements UserService {

    @Transactional(rollbackFor = Exception.class)

    public void update(User user) {


      try{

        // update user

      }catch(Execption e){

        log.error("异常",e)

      }

    }   

}

异常被抓了,这样子代理类就没办法知道你到底有没有错误,需不需要回滚,所以这种情况也是没办法回滚的哦。

8.接口层声明式事务使用cglib代理

public interface UserService {

    @Transactional(rollbackFor = Exception.class)

    public void update(User user) 

}


@Service

public class UserServiceImpl implements UserService {


    public void update(User user) {

        // update user

    }   

}

通过元素的 “proxy-target-class” 属性值来控制是基于接口的还是基于类的代理被创建。如果

“proxy-target-class” 属值被设置为

“true”,那么基于类的代理将起作用(这时需要CGLIB库cglib.jar在CLASSPATH中)。如果

“proxy-target-class” 属值被设置为 “false” 或者这个属性被省略,那么标准的JDK基于接口的代理将起作用

注解@Transactional cglib与java动态代理最大区别是代理目标对象不用实现接口,那么注解要是写到接口方法上,要是使用cglib代理,这是注解事务就失效了,为了保持兼容注解最好都写到实现类方法上。

9.rollbackFor异常指定错误

@Service

public class UserServiceImpl implements UserService {

    @Transactional

    public void update(User user) {

        // update user

    }   

}

上面这种没有指定回滚异常,这个时候默认的回滚异常是RuntimeException ,如果出现其他异常那么就不会回滚事务

总结

在这里也为大家整理了各个知识点模块整理文档(微服务、数据库、mysql、jvm、Redis等都有)和更多大厂面试真题,有需要的朋友

可以加q群:799215493   备注:简书   免费领取~

推荐阅读更多精彩内容

  • ## 面试题:spring事物失效的9大原因 #### 1.spring事物实现方式及原理 Spring 事务的本...
    sharedCode阅读 50评论 0 0
  • @Transation 注解是我们在开发中常用的注解,但是我们大多数只知道配置上就可以开启事务,很多人比如我,都不...
    北方有你南方有我阅读 64评论 0 0
  • 一、配置maven的pom.xml加载jar包 为了后续开发的方便,将SSM框架所有需要的jar包一并加载进来 p...
    docki阅读 1,570评论 1 23
  • Spring 复习 [toc] spring介绍 三层架构中spring位置,连接三层。 spring一站式框架正...
    inke阅读 358评论 0 11
  • 1.IOC与DI inverse of control 控制反转我们创建对象的方式反转了。以前对象的创建由开发人员...
    蕊er阅读 89评论 0 0