大三后端暑期实习面经总结——SSM&微服务框架篇

Posted Baret-H

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了大三后端暑期实习面经总结——SSM&微服务框架篇相关的知识,希望对你有一定的参考价值。

img
博主现在大三在读,从三月开始找暑期实习,暑假准备去tx实习啦!总结下了很多面试真题,希望能帮助正在找工作的大家!相关参考都会标注原文链接,尊重原创!



参考:


1. mvc、mvp、mvvm

MVC架构

MVC是Model-View-Controller的缩写,它将应用程序划分为三个部分:

  • Model: 模型,管理数据

  • View: 视图,展示数据

  • Controller: 控制器,处理数据

image-20210528083510080

MVP模式

MVP是Model-View-Presenter的缩写,它从MVC衍生而来,从名称上看只是将C换成了P。其他都一样。而事实上呢?它们也确实这样,P承担了C的任务而已。

同MVC的区别是:它们两个的数据流向不一样
image-20210528083554347

  • MVC框架中,V的数据从Model中拿

  • MVP框架中,V的数据从Presenter中拿。

MVVM模式

MVVM是Model-View-ViewModel的缩写,为了解决前端的响应式编程而生,由于前端网页混合了html、CSS和javascript,而且页面众多,代码的组织和维护难度复杂,所以通过ViewModel实现View和Model的双向绑定。

image-20210528083638325

2. Java服务器有哪些

Web服务器是运行及发布Web应用的容器,只有将开发的Web项目放置到该容器中,才能使网络中的所有用户通过浏览器进行访问。开发Java Web应用所采用的服务器主要是与JSP/Servlet兼容的Web服务器,比较常用的有Tomcat、Resin、JBoss、WebSphere 和 WebLogic 等,下面将分别进行介绍。

Tomcat

目前最为流行的Tomcat服务器是Apache-Jarkarta开源项目中的一个子项目,是一个小型、轻量级的支持JSP和Servlet 技术的Web服务器,也是初学者学习开发JSP应用的首选。

Resin

Resin是Caucho公司的产品,是一个非常流行的支持Servlet和JSP的服务器,速度非常快。Resin本身包含了一个支持HTML的Web服务器,这使它不仅可以显示动态内容,而且显示静态内容的能力也毫不逊色,因此许多网站都是使用Resin服务器构建。

JBoss

JBoss是一个种遵从JavaEE规范的、开放源代码的、纯Java的EJB服务器,对于J2EE有很好的支持。JBoss采用JML API实现软件模块的集成与管理,其核心服务又是提供EJB服务器,不包含Servlet和JSP的Web容器,不过它可以和Tomcat完美结合。

WebSphere

WebSphere是IBM公司的产品,可进一步细分为 WebSphere Performance Pack、Cache Manager 和WebSphere Application Server等系列,其中WebSphere Application Server 是基于Java 的应用环境,可以运行于 Sun Solaris、Windows NT 等多种操作系统平台,用于建立、部署和管理Internet和Intranet Web应用程序。

WebLogic

WebLogic 是BEA公司的产品,可进一步细分为 WebLogic Server、WebLogic Enterprise 和 WebLogic Portal 等系列,其中 WebLogic Server 的功能特别强大。WebLogic 支持企业级的、多层次的和完全分布式的Web应用,并且服务器的配置简单、界面友好。对于那些正在寻求能够提供Java平台所拥有的一切应用服务器的用户来说,WebLogic是一个十分理想的选择。


3. 跨域及其解决方式

什么是跨域?

要明白什么是跨域之前,首先要明白什么是同源策略

同源策略是一个重要的安全策略,用来限制从一个源加载的文档或脚本与来自另一个源的资源进行交互。它能帮助阻隔恶意文档,减少可能被攻击的媒介。

那怎样判断是否是同源呢?

  • 如果协议,端口(如果指定了)和主机对于两个页面是相同的,则两个页面具有相同的源,也就是同源

image-20210428202326525

跨域,指的是浏览器不能执行其他网站的脚本,它是由浏览器的同源策略所造成的,是浏览器对于JavaScript所定义的安全限制策略。

1️⃣ 使用Filter方式进行设置

使用Filter过滤器来过滤服务请求,向请求端设置Response Header(响应头部)的Access-Control-Allow-Origin属性声明允许跨域访问。

@WebFilter
public class CorsFilter implements Filter {  

    @Override
    public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain) throws IOException, ServletException {  
        HttpServletResponse response = (HttpServletResponse) res;  
        response.setHeader("Access-Control-Allow-Origin", "*");  
        response.setHeader("Access-Control-Allow-Methods", "*");  
        response.setHeader("Access-Control-Max-Age", "3600");  
        response.setHeader("Access-Control-Allow-Headers", "*");
        response.setHeader("Access-Control-Allow-Credentials", "true");
        chain.doFilter(req, res);  
    }  
}

2️⃣ 继承 HandlerInterceptorAdapter

@Component
public class CrossInterceptor extends HandlerInterceptorAdapter {

    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        response.setHeader("Access-Control-Allow-Origin", "*");
        response.setHeader("Access-Control-Allow-Methods", "GET, POST, PUT, DELETE, OPTIONS");
        response.setHeader("Access-Control-Max-Age", "3600");
        response.setHeader("Access-Control-Allow-Headers", "*");
        response.setHeader("Access-Control-Allow-Credentials", "true");
        return true;
    }
}

3️⃣ 实现WebMvcConfigurer

@Configuration
@SuppressWarnings("SpringJavaAutowiredFieldsWarningInspection")
public class AppConfig implements WebMvcConfigurer {

    @Override
    public void addCorsMappings(CorsRegistry registry) {
        registry.addMapping("/**")  // 拦截所有的请求
                .allowedOrigins("http://www.abc.com")  // 可跨域的域名,可以为 *
                .allowCredentials(true)
                .allowedMethods("*")   // 允许跨域的方法,可以单独配置
                .allowedHeaders("*");  // 允许跨域的请求头,可以单独配置
    }
}

4️⃣ 使用Nginx配置

location / {
   add_header Access-Control-Allow-Origin *;
   add_header Access-Control-Allow-Headers X-Requested-With;
   add_header Access-Control-Allow-Methods GET,POST,PUT,DELETE,OPTIONS;

   if ($request_method = 'OPTIONS') {
     return 204;
   }
}

5️⃣ 使用 @CrossOrgin 注解

如果只是想部分接口跨域,且不想使用配置来管理的话,可以使用这种方式

  • 在Controller使用

    @CrossOrigin
    @RestController
    @RequestMapping("/user")
    public class UserController {
    
    	@GetMapping("/{id}")
    	public User get(@PathVariable Long id) {
    		
    	}
    
    	@DeleteMapping("/{id}")
    	public void remove(@PathVariable Long id) {
    
    	}
    }
    
  • 在具体接口上使用

    @RestController
    @RequestMapping("/user")
    public class UserController {
    
    	@CrossOrigin
    	@GetMapping("/{id}")
    	public User get(@PathVariable Long id) {
    		
    	}
    
    	@DeleteMapping("/{id}")
    	public void remove(@PathVariable Long id) {
    
    	}
    }
    

6️⃣ Spring Cloud Gateway 跨域配置

spring: 
  cloud:
    gateway:
      globalcors:
        cors-configurations:
          '[/**]':
            // 允许跨域的源(网站域名/ip),设置*为全部
            // 允许跨域请求里的head字段,设置*为全部
            // 允许跨域的method,默认为GET和OPTIONS,设置*为全部
            allow-credentials: true
            allowed-origins:
              - "http://xb.abc.com"
              - "http://sf.xx.com"
            allowed-headers: "*"
            allowed-methods:
              - OPTIONS
              - GET
              - POST
              - DELETE
              - PUT
              - PATCH
            max-age: 3600

注意: 通过gateway 转发的其他项目,不要进行配置跨域配置

有时即使配置了也不会起作用,这时你可以根据浏览器控制的错误输出来查看问题,如果提示是 response 中 header 出现了重复的 Access-Control-* 请求头,可以进行如下操作

import java.util.ArrayList;
import org.springframework.cloud.gateway.filter.GatewayFilterChain;
import org.springframework.cloud.gateway.filter.GlobalFilter;
import org.springframework.cloud.gateway.filter.NettyWriteResponseFilter;
import org.springframework.core.Ordered;
import org.springframework.http.HttpHeaders;
import org.springframework.stereotype.Component;
import org.springframework.web.server.ServerWebExchange;
import reactor.core.publisher.Mono;

@Component("corsResponseHeaderFilter")
public class CorsResponseHeaderFilter implements GlobalFilter, Ordered {

  @Override
  public int getOrder() {
    // 指定此过滤器位于NettyWriteResponseFilter之后
    // 即待处理完响应体后接着处理响应头
    return NettyWriteResponseFilter.WRITE_RESPONSE_FILTER_ORDER + 1;
  }

  @Override
  public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
    return chain.filter(exchange).then(Mono.defer(() -> {
      exchange.getResponse().getHeaders().entrySet().stream()
          .filter(kv -> (kv.getValue() != null && kv.getValue().size() > 1))
          .filter(kv -> (
              kv.getKey().equals(HttpHeaders.ACCESS_CONTROL_ALLOW_ORIGIN)
                  || kv.getKey().equals(HttpHeaders.ACCESS_CONTROL_ALLOW_CREDENTIALS)
                  || kv.getKey().equals(HttpHeaders.ACCESS_CONTROL_ALLOW_METHODS)
                  || kv.getKey().equals(HttpHeaders.ACCESS_CONTROL_ALLOW_HEADERS)
                  || kv.getKey().equals(HttpHeaders.ACCESS_CONTROL_MAX_AGE)))
          .forEach(kv -> {
            kv.setValue(new ArrayList<String>() {{
              add(kv.getValue().get(0));
            }});
          });
      return chain.filter(exchange);
    }));
  }
}

4. MyBatis优缺点

优点

  1. 基于SQL语句编程,相当灵活,不会对应用程序或者数据库的现有设计造成任何影响,SQL写在xml里,解除sql与程序代码的耦合,便于统一管理;提供xml标签,支持编写动态SQL语句,并可重用
  2. 与JDBC相比,减少了50%以上的代码量,消除了JDBC大量冗余的代码,不需要手动开关连接
  3. 很好的与各种数据库兼容,因为MyBatis使用JDBC来连接数据库,所以只要JDBC支持的数据库 MyBatis都支持
  4. 能够与Spring很好的集成
  5. 提供映射标签,支持对象与数据库的ORM字段关系映射;提供对象关系映射标签,支持对象关系组件维护

缺点

  1. SQL语句的编写工作量较大,尤其当字段多、关联表多时,对开发人员编写SQL语句的功底有一定要求。
  2. SQL语句依赖于数据库,导致数据库移植性差,不能随意更换数据库。

5. #{}和${}的区别是什么

#{}是预编译处理,是占位符;${}是字符串替换,是拼接符

  • Mybatis在处理#{}时,会将sql中的#{}替换为?号,调用PreparedStatement来赋值
  • Mybatis在处理${}时,就是把${}替换成变量的值,调用Statement来赋值
  • #{}的变量替换是在DBMS中、变量替换后,#{}对应的变量自动加上单引号
  • ${}的变量替换是在DBMS外、变量替换后,${}对应的变量不会加上单引号
  • 使用#{}可以有效的防止SQL注入,提高系统安全性

6. 简述Mybatis的插件运行原理,如何编写一个插件

Mybatis的插件本质上指的就是Mybatis的拦截器,它只能拦截ParameterHandlerResultSetHandlerStatementHandlerExecutor四个接口,所以Mybatis拦截器实现的功能是很有限的。

拦截原理:Mybatis使用jdk的动态代理,为需要拦截的接口生成代理对象以实现接口方法的拦截功能,每当执行这四种接口对象的方法时,就会进入拦截方法,具体就是 InvocationHandler中的invoke()方法,拦截指定的方法

image-20210505134827399


7. Spring是什么

1️⃣ 轻量级开源的J2EE框架

  • 它是一个容器框架,可以用来存放JavaBean对象
  • 它是一个中间层框架(万能胶),可以起连接作用,整合其他框架使用,让企业开发更快更简洁

2️⃣ 轻量级的控制反转(IoC)和面向切面(AOP)的容器框架

  • 从大小和开销来说spring都是轻量级
  • 通过控制反转IoC达到了松耦合的目的
  • 提供了面向切面编程AOP的丰富支持——允许通过分离应用的业务逻辑与系统级服务来进行内聚性的开发
  • 包含并管理应用JavaBean的配置和声明周期,这个意义上是一个容器
  • 将简单的组件配置组合成为复杂的应用,这个意义上是一个框架

8. 对AOP的理解

一个系统是由不同的组件组成的,每个组件都负责一块特定的业务,实现自己的核心功能;此外,这些组件可能还会有额外的任务。比如日志、事务管理、安全保障等业务,这些业务常常需要融入到不同组件的核心功能中,会跨越系统的多个组件,这些额外的需求在AOP中被称为横切关注点

当我们需要为这些分散的组件引入公共的需求的时候,OOP就显得无能为力,因为面向对象编程的思想会将这额外的业务定义成一个个业务类然后插入到每个组件的核心业务中,十分麻烦,会有大量代码的重复,不利于各个模块的复用。AOP就能很好的解决这些问题。

AOP:将程序中的交叉业务逻辑(比如安全、日志、事务等)封装成一个切面,然后注入到目标对象的具体业务逻辑中。AOP可以对某个对象或者某个对象的某些功能进行增强,比如对对象方法的增强,可以在方法的前后添加额外的功能

使用“横切”技术,AOP把软件系统分为两个部分:核心关注点和横切关注点。业务处理的主要流程是核心关注点,与之关系不大的部分是横切关注点。横切关注点的一个特点是,他们经常发生在核心关注点的多处,而各处都基本相似。比如权限认证、日志、事务处理。Aop 的作用在于分离系统中的各种关注点,将核心关注点和横切关注点分离开来。正如Avanade公司的高级方案构架师Adam Magee所说,AOP的核心思想就是“将应用程序中的商业逻辑同对其提供支持的通用服务进行分离。”


9. 对IoC的理解

从三个方面来回答:容器概念控制反转依赖注入

1️⃣Ioc容器:本质上就是一个map(key-value),里面存放了各种对象:

  • xml中配置的bean结点

  • @Repository、@Service、@Controller、@Conponent标注的类

在项目启动的时候会读取配置文件中的的bean结点,扫描以上注解标时的类,根据全限定类名通过反射创建对象存放到map中;

2️⃣ 控制反转:没有引入IoC容器之前,对象A依赖于对象B,那么对象A在初始化或者运行到某一点的时候,自己必须主动去创建对象B或者使用已经创建的对象B。无论是创建还是使用对象B,控制权都在自己手上。

引入IoC容器之后,对象A与对象B之间失去了直接联系,当对象A运行到需要对象B的时候,IoC容器会主动创建一个对象B注入到对象A需要的地方。

通过前后的对比,不难看出来:对象A获得依赖对象B的过程,由主动行为变为了被动行为,控制权颠倒过来了,这就是“控制反转这个名称的由来

全部对象的控制权全部上缴给"第三方"IoC容器,所以IoC容器成了整个系统的关键核心,它起到了一种类似“粘合剂的作用,把系统中的所有对象粘合在一起发挥作用,如果没有这个“粘合剂,对象与对象之间会彼此失去联系,这就是有人把IoC容器比喻成“粘合剂"的由来。

3️⃣ 依赖注入:DI是IoC的一种实现方式,就是由IoC容器在运行期间,动态地将某种依赖关系注入到对象之中。


10. 如何实现一个IoC容器

image-20210429220408198


11. BeanFactory和ApplicationContext的区别

ApplicationContextBeanFactory的子接口,体统了更完整的功能:

  • 继承MessageSource,因此支持国际化
  • 统一的资源文件访问方式
  • 提供在监听器中注册bean的事件
  • 同时加载多个配置文件
  • 载入多个(有继承关系)上下文,是的每一个上下文都专注于一个特定的层次,比如应用的web层

区别:

  • BeanFactory采用延迟加载的形式来注入Bean,即只有在使用到某个Bean,也就是调用getBean()方法时,在对Bean进行加载实例化。这样我们在容器启动的时候就不能发现spring存在的配置问题,比如Bean的某个属性没有注入,直到BeanFactory加载后第一次调用getBean()方法才会抛出异常
  • ApplicationContext在容器启动时一次性创建了所有的Bean。这样就能在容器启动的时候发现Spring中存在的配置问题,有利于检查所依赖属性是否注入。ApplicationContext启动后预载入所有的单实例Bean,通过预载入单实例Bean,确保需要使用的时候无需等待,因为已经创建好了
  • 相对于基本的BeanFactoryApplicationContext唯一的不足是占用内存空间,当应用程序配置了很多的Bean时,程序启动较慢
  • BeanFactory通常以编程的方式创建,ApplicationContext可以以声明的方式创建(使用ContextLoader)
  • 两者都支持后置处理器BeanPostProcessor、BeanFactoryPostProcessor,但区别是:BeanFactory需要手动注册,而ApplicationContext是自动注册

12. Spring Bean的生命周期

img

1️⃣ 实例化

  • 首先扫描路径解析类得到BeanDefinition,它描述了bean对象的一系列信息
  • 然后通过构造方法实例化出一个对象(如果由多个构造方法,需要推断构造方法)

2️⃣ 属性赋值

  • 对加了@Autowired等注解的对象的进行属性的赋值

3️⃣ 注入Aware接口

  • Spring会检测该对象是否实现了xxxAware接口,并将相关的xxxAware实例注入给bean

4️⃣ 前置处理

  • 当经过上述几个步骤后,bean对象已经被正确构造,但如果你想要对象被使用前再进行一些自定义的处理,就可以继承BeanPostProcessor接口实现其前置处理方法,这个方法会先于InitialzationBean执行,因此称为前置处理

    //当前正在初始化的bean对象会被传递进来,我们就可以对这个bean作任何处理。
    //这个函数会先于InitialzationBean执行,因此称为前置处理。
    postProcessBeforeInitialzation( Object bean, String beanName )
    

5️⃣ 初始化

  • 对bean实例进行初始化:InitializingBean

6️⃣ 后置处理

  • 在bean初始化完成后可以进行后置处理,它与前置处理不同,由于该函数并不会把当前bean对象传进来,因此在这一步没办法处理对象本身,只能增加一些额外的逻辑,AOP通常就在此实现

    //当前正在初始化的bean对象会被传递进来,我们就可以对这个bean作任何处理。
    //这个函数会在InitialzationBean完成后执行,因此称为后置处理。
    postProcessAfterInitialzation( Object bean, String beanName )
    

7️⃣ 使用bean

  • 如果bean是单例的,还会将其放入单例池然后使用

8️⃣ 销毁bean

  • Spring容器关闭时调用DisposableBeandestory()方法

13. Spring支持的bean作用域

当通过spring容器创建一个Bean实例时,不仅可以完成Bean实例的实例化,还可以为Bean指定特定的作用域。Spring支持如下5种作用域:

  • singleton:默认的单例模式,每个容器中只有一个bean实例,单例的模式由BeanFactory(第一次注入时创建)自身来维护。该对象的生命周期与Spring IoC容器一致
  • prototype:原型模式,为每一个bean都提供一个实例,每次注入都会创建一个对象
  • request:每个HTTP请求都会为bean创建一个实例,请求结束该实例回收
  • session:与request类似,每个session中有一个bean实例,session过期后该实例回收
  • application:在ServletContext的生命周期中复用一个单例对象
  • websocket:在websocket的声明周期中复用一个单例对象
  • global-session:每个全局的HTTP Session,使用session定义的Bean都将产生一个新实例。典型情况下,仅在使用portlet context的时候有效。同样只有在Web应用中使用Spring时,该作用域才有效

其中比较常用的是singleton和prototype两种作用域。对于singleton作用域的Bean,每次请求该Bean都将获得相同的实例。容器负责跟踪Bean实例的状态,负责维护Bean实例的生命周期行为;如果一个Bean被设置成prototype作用域,程序每次请求该id的Bean,Spring都会新建一个Bean实例,然后返回给程序。在这种情况下,Spring容器仅仅使用new 关键字创建Bean实例,一旦创建成功,容器不在跟踪实例,也不会维护Bean实例的状态。

如果不指定Bean的作用域,Spring默认使用singleton作用域。Java在创建Java实例时,需要进行内存申请;销毁实例时,需要完成垃圾回收,这些工作都会导致系统开销的增加。因此,prototype作用域Bean的创建、销毁代价比较大。而singleton作用域的Bean实例一旦创建成功,可以重复使用。因此,除非必要,否则尽量避免将Bean被设置成prototype作用域。


14. Spring中的bean是线程安全的吗

在Spring中,bean默认作用域是单例的,在spring容器中全局共享,框架并没有对bean进行多线程的封装,会存在多线程访问的问题,并不安全

首先搞清楚什么是有状态、什么是无状态

  • 有状态指的是有数据存储的功能
  • 无状态就是不会保存数据

如果Bean是有状态的,那么就需要由我们来进行线程安全的保证,最简单的方法就是改变bean的作用域,将singleton改为protopyte,这样每次请求bean就相当于new Bean(),这样就可以保证线程安全了

此外,还可以用ThreadLocal来确保安全,例如Dao层与数据库进行交互,会操作Connection对象,Connection对象就是带有状态的,比如数据库事务的操作,Spring的事务管理器就是使用ThreadLocal为不同线程维护了一套独立的connection副本来保证线程之间不会相互影响

不要在bean中声明任何有状态的实例变量或类变量,如果必须如此,那么就使用 Threadloca把变量变为线程私有的,如果bean的实例变量或类变量需要在多个线程之间共享,那么就只能使用 synchronized、Lock、CAS等这些实现线程同步的方法了。


15. Spring中的设计模式及使用场景

1️⃣ 简单工厂:由一个工厂类根据传入的参数,动态决定创建哪一个产品类

spring中的BeanFactory就是简单工厂模式的体现,根据传入一个唯一的标识来获得Bean对象,但是否是在传入参数后创建还是传入参数前创建这个要根据具体情况来定。


2️⃣ 工厂方法

实现了FactoryBean接口的bean是一类叫做factory的bean,其特点是:spring在使用getBean()获得bean时,会自动调用该类bean的getObject()方法,所以返回的不是这个bean,而是bean.getObject()的返回值


3️⃣ 适配器模式

spring定义了一个适配接口,使得每一种Controller有一种对应的适配器实现类,让适配器代替controller执行相应的方法。这样在扩展 Controller时,只需要增加一个适配器类就完成了SpringMVC的扩展了


4️⃣ 装饰器模式:动态地给一个对象添加一些额外的职责。就増加功能来说,Decorator模式相比生成子类更为灵活。

Spring中用到的包装器模式在类名上有两种表现:一种是类名中含有Wrapper,另一种是类名中含有Decorator


5️⃣ 动态代理

织入:把切面应用到目标对象并创建新的代理对象的过程。

切面在运行时被织入,一般情况下,在织入切面时,AOP容器会未目标对象动态创建一个代理对象,SpringAOP就是以这种方式织入切面的


6️⃣ 观察者模式

spring的事件驱动模型使用的是观察者模式,Spring中observer模式常用的地方是listener的实现


7️⃣ 策略模式

Spring框架的资源访问Resource接口。该接口提供了更强的资源访问能力,Spring框架本身大量使用了Resource接口来访问底层资源。


16. Spring事务的实现方式

image-20210430090333312

1️⃣ 编程式

编程式事务管理对基于 POJO 的应用来说是唯一选择。我们需要在代码中调用beginTransaction()、commit()、rollback()等事务管理相关的方法,这就是编程式事务管理。

2️⃣ 声明式

  1. 基于 TransactionProxyFactoryBean 的声明式事务管理
  2. 基于 @Transactional 的声明式事务管理
  3. 基于 Aspectj AOP 配置事务

基于 Aspectj AOP 配置事务具体流程

1️⃣ 开启Spring的事务处理功能

创建一个 DataSourceTransactionManager 对象,传入上述创建好的dataSource对象

<!--配置声明式事务-->
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
    <property name="dataSource" ref="dataSource"/>
</bean>

2️⃣ 配置事务通知

这里使用事务tx命名空间配置

常用的两个属性

  • name属性规定配置事务的方法

  • propagation属性配置事务的传播特性,默认为REQUIRED

REQUIRED支持当前事务,如果当前没有事务,就新建一个事务
REQUIRED_NEW新建事务,如果当前存在事务,把当前事务挂起
SUPPORTS支持当前事务,如果当前没有事务,就以非事务方式执行
NOT_SUPPORTED以非事务方式执行操作,如果当前存在事务,就把当前事务挂起
MANDATORY支持当前事务,如果当前没有事务,就抛出异常
NEVER以非事务方式执行,如果当前存在事务,则抛出异常
NESTED支持当前事务,如果当前事务存在,则执行一个嵌套事务,如果当前没有事务,就新建一个事务
<!--配置事务通知-->
<tx:advice id="txAdvice" transaction-manager="transactionManager">
    <!--name给哪写方法配置事务-->
    <!--propagation配置事务传播特性-->
    <tx:attributes>
        <以上是关于大三后端暑期实习面经总结——SSM&微服务框架篇的主要内容,如果未能解决你的问题,请参考以下文章

大三Java后端暑期实习面经总结——Java基础篇

大三Java后端暑期实习面经总结——Java基础篇

大三后端暑期实习面经总结——MySQL篇

大三后端暑期实习面经总结——MySQL篇

大三Java后端暑期实习面经总结——Java容器篇

大三Java后端暑期实习面经总结——Java容器篇