spring总结

0、Spring,Spring MVC,Spring Boot 之间什么关系?

Spring 包含了多个功能模块,其中最重要的是 Spring-Core(主要提供 IoC 依赖注入功能的支持) 模块, Spring 中的其他模块(比如 Spring MVC)的功能实现基本都需要依赖于该模块。

Spring MVC 是 Spring 中的一个很重要的模块,主要赋予 Spring 快速构建 MVC 架构的 Web 程序的能力。MVC 是模型(Model)、视图(View)、控制器(Controller)的简写,其核心思想是通过将业务逻辑、数据、显示分离来组织代码。

spring总结_第1张图片

使用 Spring 进行开发各种配置过于麻烦比如开启某些 Spring 特性时,需要用 XML 或 Java 进行显式配置。于是,Spring Boot 诞生了!

Spring 旨在简化 J2EE 企业应用程序开发。Spring Boot 旨在简化 Spring 开发(减少配置文件,开箱即用!)。Spring Boot 只是简化了配置,如果你需要构建 MVC 架构的 Web 程序,你还是需要使用 Spring MVC 作为 MVC 框架,只是说 Spring Boot 帮你简化了 Spring MVC 的很多配置,真正做到开箱即用!

J2SE全称是java 2 Standard Edition(标准版), J2SE 包含那些构成Java语言核心的类。比如:数据库连接、接口定义、输入/输出、网络编程

J2EE全称是java 2 enterprise edition(企业版),现在最新称谓是java EE 5,两个是同样的东东,Enterprise Edition(企业版) J2EE 包含J2SE 中的类,并且还包含用于开发企业级应用的类。比如:EJB、servlet、JSP、XML、事务控制 。

J2SE包含于J2EE中,简单点说,J2EEJ2SE在企业应用需求上的扩张,语法是以J2SE为基础,通过添加新的API,框架技术来实现大规模,高复杂度的企业级项目的开发。

一、Spring

1、AOP

概念;几个名词解释;JDK VS Cglib;通知(5)

AOP实现的关键在于 代理模式,AOP代理主要分为静态代理和动态代理。静态代理的代表为AspectJ;动态代理则以Spring AOP为代表。

将 Advice 应用于目标对象后创建的对象称为代理。在客户端对象的情况下,目标对象和代理对象是相同的。

Advice + Target Object = Proxy

技术实现:Spring AOP,AspectJ(xml和注解)

Spring AOP 和 AspectJ AOP 有什么区别

Spring AOP 属于运行时增强,而 AspectJ 是编译时增强。

Spring AOP 基于代理(Proxying),而 AspectJ 基于字节码操作(Bytecode Manipulation)。

2、IOC

概述;比如淘宝。优点:第一,资源集中管理,实现资源的可配置和易管理。第二,降低了使用资源双方的依赖程度,也就是我们说的耦合度。

什么是DI?DI 是 IoC 的技术实现,就是注入属性,必须在创建对象的基础上进行。DI(dependency injection):依赖注入,只需在程序中提供要使用的对象名称即可,至于对象如何在容器中创建、赋值、查找都由容器内部实现。在Spring创建对象的过程中,把对象依赖的属性注入到对象中。依赖注入主要有两种方式:构造器注入和属性注入。

DI实现方式:xml和注解

xml:使用标签和属性完成。包括set注入(property标签)和构造器注入( constructor-arg标签)。

若类中的属性为引用类型,如 Student 类中有自定义类 School,可采用 ref 标签属性引用。


    
    
    

    
    

IOC容器初始化过程

  1. 从XML中读取配置文件。

  2. 将bean标签解析成 BeanDefinition,如解析 property 元素, 并注入到 BeanDefinition 实例中。

  3. 将 BeanDefinition 注册到容器 BeanDefinitionMap 中。

  4. BeanFactory 根据 BeanDefinition 的定义信息创建实例化和初始化 bean。

单例bean的初始化以及依赖注入一般都在容器初始化阶段进行,只有懒加载(lazy-init为true)的单例bean是在应用第一次调用getBean()时进行初始化和依赖注入。

// AbstractApplicationContext
// Instantiate all remaining (non-lazy-init) singletons.
finishBeanFactoryInitialization(beanFactory);

多例bean 在容器启动时不实例化,即使设置 lazy-init 为 false 也没用,只有调用了getBean()才进行实例化。

loadBeanDefinitions采用了模板模式,具体加载 BeanDefinition 的逻辑由各个子类完成。

3、Bean

什么是bean?Bean 代指的就是那些被 IoC 容器所管理的对象。

将一个类声明为 Bean 的注解有哪些?

作用域(2+4);生命周期(4大类:实例化 Instantiation;属性赋值 Populate;初始化 Initialization;销毁 Destruction)

单例 Bean 的线程安全问题了解吗?

大部分时候我们并没有在项目中使用多线程,所以很少有人会关注这个问题。单例 Bean 存在线程问题,主要是因为当多个线程操作同一个对象的时候是存在资源竞争的。常见的有两种解决办法:

  1. 在 Bean 中尽量避免定义可变的成员变量。

  2. 在类中定义一个 ThreadLocal 成员变量,将需要的可变成员变量保存在 ThreadLocal 中(推荐的一种方式)。

不过,大部分 Bean 实际都是无状态(没有实例变量)的(比如 Dao、Service),这种情况下, Bean 是线程安全的。

将一个类声明为 Bean 的注解有哪些?(4)

@Component@Repository@Service@Controller

@Repository : 对应持久层即 Dao 层,主要用于数据库相关操作。


@Component 和 @Bean 的区别是什么?

都是使用注解定义 Bean。@Bean 是使用 Java 代码装配 Bean,@Component 是自动装配 Bean。

@Component 注解用在类上,表明一个类会作为组件类,并告知Spring要为这个类创建bean,每个类对应一个 Bean。

@Bean 注解用在方法上,表示这个方法会返回一个 Bean。@Bean 需要在配置类中使用,即类上需要加上@Configuration注解。

Spring常用的注入方式有:属性注入, 构造方法注入, set 方法注入

  • 构造器注入:利用构造方法的参数注入依赖

  • set方法注入:调用setter的方法注入依赖

  • 属性注入:在字段上使用@Autowired/Resource注解

其中,基于属性注入的方式,容易导致Spring 初始化失败。因为在Spring在初始化的时候,可能由于属性在被注入前就引用而导致空指针异常,进而导致容器初始化失败。如果可能的话,尽量使用构造器注入。@Autowired默认是按照类型匹配(ByType),因此有可能会出现两个相同的类型bean,进而导致Spring 装配失败。

@Autowired 和 @Resource 的区别是什么?

  • @Autowired 是 Spring 提供的注解,@Resource 是 JDK 提供的注解。

  • @Autowired 默认的注入方式为byType(根据类型进行匹配),@Resource默认注入方式为 byName(根据名称进行匹配)。

  • 当一个接口存在多个实现类的情况下,@Autowired@Resource都需要通过名称才能正确匹配到对应的 Bean。Autowired 可以通过 @Qualifier 注解来显式指定名称,@Resource可以通过 name 属性来显式指定名称。

  • @Reference是Dubbo框架中的注解,用于注入Dubbo中的远程服务对象。它的使用方式有两种:

    • 根据类型自动装配:如果@Reference注解修饰的属性的类型在Dubbo中只有一个对应的服务对象,那么Dubbo会将该服务对象自动注入到该属性中。

    • 根据名称自动装配:如果@Reference注解修饰的属性的类型在Dubbo中有多个对应的服务对象,那么Dubbo会根据属性名称或者注解中指定的名称来选择要注入的服务对象。

上述两种自动装配的依赖注入并不适合简单值类型,如int、boolean、long、String以及Enum等,对于这些类型,Spring容器也提供了@Value注入的方式。

@Value和@Autowired、@Resource类似,也是用来对属性进行注入的,只不过@Value是用来从Properties文件中来获取值的,并且@Value可以解析SpEL(Spring表达式)。


BeanFactory和FactoryBean的区别?

BeanFactory:管理Bean的容器,Spring中生成的Bean都是由这个接口的实现来管理的。

FactoryBean:通常是用来创建比较复杂的bean,一般的bean 直接用xml配置即可,但如果一个bean的创建过程中涉及到很多其他的bean 和复杂的逻辑,直接用xml配置比较麻烦,这时可以考虑用FactoryBean,可以隐藏实例化复杂Bean的细节。

BeanFactory和ApplicationContext有什么区别?

BeanFactory和ApplicationContext是Spring的两大核心接口,都可以当做Spring的容器。其中ApplicationContext是BeanFactory的子接口。

  • 功能上的区别。ApplicationContext接口作为BeanFactory的派生,除了提供BeanFactory所具有的功能外,还提供了更完整的框架功能,如继承MessageSource、支持国际化、统一的资源文件访问方式、同时加载多个配置文件等功能。

  • 加载方式的区别。BeanFactroy采用的是延迟加载形式来注入Bean的,即只有在使用到某个Bean时(调用getBean()),才对该Bean进行加载实例化。而ApplicationContext是在容器启动时,一次性创建了所有的Bean。

  • 创建方式的区别。BeanFactory通常以编程的方式被创建,ApplicationContext还能以声明的方式创建,如使用ContextLoader。

4、事务

两种事务管理;事务失效(6)

1、@Transactional 应用在非 public 修饰的方法上

如果Transactional注解应用在非public 修饰的方法上,Transactional将会失效。

之所以会失效是因为在Spring AOP 代理时,TransactionInterceptor (事务拦截器)在目标方法执行前后进行拦截,DynamicAdvisedInterceptor(CglibAopProxy 的内部类)的 intercept 方法或 JdkDynamicAopProxy 的 invoke 方法会间接调用 AbstractFallbackTransactionAttributeSourcecomputeTransactionAttribute方法,获取Transactional 注解的事务配置信息。

此方法会检查目标方法的修饰符是否为 public,不是 public则不会获取@Transactional 的属性配置信息。

注意:protectedprivate 修饰的方法上使用 @Transactional 注解,虽然事务无效,但不会有任何报错,这是我们很容犯错的一点。

2、@Transactional 注解属性 propagation 设置错误

这种失效是由于配置错误,若是错误的配置以下三种 propagation,事务将不会发生回滚。

TransactionDefinition.PROPAGATION_SUPPORTS:如果当前存在事务,则加入该事务;如果当前没有事务,则以非事务的方式继续运行。

TransactionDefinition.PROPAGATION_NOT_SUPPORTED:以非事务方式运行,如果当前存在事务,则把当前事务挂起。

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

3、@Transactional 注解属性 rollbackFor 设置错误

rollbackFor 可以指定能够触发事务回滚的异常类型。Spring默认抛出了未检查unchecked异常(继承自 RuntimeException 的异常)或者 Error才回滚事务;其他异常不会触发回滚事务。如果在事务中抛出其他类型的异常,但却期望 Spring 能够回滚事务,就需要指定 rollbackFor 属性,如果未指定 rollbackFor 属性则事务不会回滚。

4、同一个类中方法调用,导致 @Transactional 失效

开发中避免不了会对同一个类里面的方法调用,比如有一个类Test,它的一个方法A,A再调用本类的方法B(不论方法B是用public还是private修饰),但方法A没有声明注解事务,而B方法有。则外部调用方法A之后,方法B的事务是不会起作用的。这也是经常犯错误的一个地方。

同一个类中,没有加事务的方法调用加了事务的方法,将会导致事务的失效。

那为啥会出现这种情况?其实这还是由于使用 Spring AOP代理造成的,因为 只有当事务方法被 当前类以外的代码 调用时,才会由Spring生成的代理对象来管理。

5、异常被你的 catch“吃了”导致 @Transactional 失效

这种情况是最常见的一种 @Transactional 注解失效场景,

@Transactional
private Integer A() throws Exception {
    int insert = 0;
    try {
        CityInfoDict cityInfoDict = new CityInfoDict();
        cityInfoDict.setCityName("2");
        cityInfoDict.setParentCityId(2);
        /**
         * A 插入字段为 2的数据
         */
        insert = cityInfoDictMapper.insert(cityInfoDict);
        /**
         * B 插入字段为 3的数据
         */
        b.insertB();
    } catch (Exception e) {
        e.printStackTrace();
    }
}

如果B方法内部抛了异常,而A方法此时try catch了B方法的异常,那这个事务还能正常回滚吗?

答案:不能!

会抛出异常:

org.springframework.transaction.UnexpectedRollbackException: Transaction rolled back because it has been marked as rollback-only

因为当ServiceB中抛出了一个异常以后,ServiceB标识当前事务需要rollback。但是ServiceA中由于你手动的捕获这个异常并进行处理,ServiceA认为当前事务应该正常commit。此时就出现了前后不一致,也就是因为这样,抛出了前面的UnexpectedRollbackException异常。

6、数据库引擎不支持事务

这种情况出现的概率并不高,事务能否生效数据库引擎是否支持事务是关键。常用的MySQL数据库默认使用支持事务的innodb引擎。一旦数据库引擎切换成不支持事务的myisam,那事务就从根本上失效了。

@Transactional 的常用配置参数总结:

属性名 说明
propagation 事务的传播行为,默认值为 REQUIRED。7个
isolation 事务的隔离级别,默认值采用 DEFAULT。5个
timeout 事务的超时时间,默认值为-1(不会超时)。如果超过该时间限制但事务还没有完成,则自动回滚事务。
readOnly 指定事务是否为只读事务,默认值为 false。
rollbackFor 用于指定能够触发事务回滚的异常类型,并且可以指定多个异常类型。

@Transactional 的工作机制是基于 AOP 实现的,AOP 又是使用动态代理实现的。如果目标对象实现了接口,默认情况下会采用 JDK 的动态代理,如果目标对象没有实现了接口,会使用 CGLIB 动态代理。如果一个类或者一个类中的 public 方法上被标注@Transactional 注解的话,Spring 容器就会在启动的时候为其创建一个代理类,在调用被@Transactional 注解的 public 方法的时候,实际调用的是代理类的方法,也就是TransactionInterceptor 类中的 invoke()方法。

若同一类中的其他没有 @Transactional 注解的方法内部调用有 @Transactional 注解的方法,有@Transactional 注解的方法的事务会失效。这是由于Spring AOP代理的原因造成的,因为只有当 @Transactional 注解的方法在类以外被调用的时候,Spring 事务管理才生效。

5、Spring 的事件流程总结

  1. 定义一个事件: 实现一个继承自 ApplicationEvent,并且写相应的构造函数;

  2. 定义一个事件监听者:实现 ApplicationListener 接口,重写 onApplicationEvent() 方法;

  3. 使用事件发布者发布消息: 可以通过 ApplicationEventPublisherpublishEvent() 方法发布消息。

5、设计模式

二、Spring Boot

1、@SpringBootApplication

  1. @EnableAutoConfiguration:启用 SpringBoot 的自动配置机制

    • @AutoConfigurationPackage:给容器中导入一个组件 Registrar.class,而 Registrar 给容器中批量导入组件,通过 registerBeanDefinitions 方法中的 PackageImports 方法,将主程序类下的所有包(子包)下的组件导入到容器中。

    • @Import(EnableAutoConfigurationImportSelector.class):使用@Import导入的类会被Spring加载到IOC容器中.AutoConfigurationImportSelector 类实现了 ImportSelector接口,也就实现了这个接口中的 selectImports方法,该方法主要用于获取所有符合条件的类的全限定类名,这些类需要被加载到 IoC 容器中

  • 获取需要自动装配的所有配置类,读取META-INF/spring.factories,可发现META-INF/spring.factories下的 xxxAutoConfiguration 被读取到了,不光是这个依赖下的META-INF/spring.factories被读取到,所有 Spring Boot Starter 下的META-INF/spring.factories都会被读取到。

    到这里可能面试官会问你:“spring.factories中这么多配置,每次启动都要全部加载么?”。

    很明显,这是不现实的。经过 filter 筛选后,根据条件装配 @ConditionalOnXXX 注解,只有满足该注解的 xxxAutoConfiguration 才会被加载,因此所需大大减小。

  1. @ComponentScan: 扫描被@Component (@Service,@Controller)注解的 bean,注解默认会扫描该类所在的包下所有的类。也可以自定义不扫描某些 bean

  2. @SpringBootConfiguration:内部是@Configuration:声明是一个配置类,允许在 Spring 上下文中注册额外的 bean 或导入其他配置类

2、启动流程

三、SpringMVC

1、异常处理

  • 在类上面加 @ControllerAdvice

  • 在类中的方法上加 @ExceptionHandler

SpringMVC使用 ExceptionHandlerExceptionResolver 来支持这种自定义异常处理机制。它是一个异常处理器,它用于处理在 MVC 组件中抛出的异常。这种异常处理方式下,会给所有或者指定的 Controller织入异常处理的逻辑(AOP),当 Controller中的方法抛出异常的时候,由被@ExceptionHandler注解修饰的方法进行处理。

ExceptionHandlerExceptionResolver 中有个参数exceptionHandlerCache ,再缓存中存放对应的错误和处理的方法。然后从ExceptionHandlerMethodResolver 去找该 exception 对应的异常处理方法。检查缓存中是否有该异常类型所对应的处理方法,如果找到了,则调用该方法来处理异常。否则,异常会被传递到上层处理器来处理。具体实现是ExceptionHandlerMethodResolver 中的getMappedMethod方法

private final Map, ExceptionHandlerMethodResolver> exceptionHandlerCache = new ConcurrentHashMap(64);

https://pict-picgo.oss-cn-hangzhou.aliyuncs.com/picture3/202209191600196.png

其他方法

1.自定义实现 HandlerExceptionResolver 接口处理异常;可以作为默认的全局异常处理规则。 catch 到 @Controller 方法执行时发生的异常,处理后返回 ModelAndView 作为结果视图,因此可以通过它来定制异常视图。

2.基于注解的处理:SimpleMappingExceptionResolver是Spring MVC提供的简单异常处理器

2、Spring MVC 的拦截器

拦截器(类)需要实现 HandlerInterceptor 接口,拦截器是全局的,可对多个 Controller 做拦截处理,一个项目中可有零个或多个拦截器,常用在用户登录、权限检查、记录日志等。拦截器使用的是 AOP 的思想,对请求统一拦截处理。

和 Filter 过滤器有什么差别?

有以下几点:

  • 功能相同:拦截器和 Filter 都能实现相应的功能

  • 容器不同:Filter属于Servlet技术;Interceptor属于SpringMVC技术

  • 使用便利性不同:拦截器提供了三个方法(preHandle、postHandle、afterCompletion),分别在不同的时机执行(在 Controller 方法处理之前被执行;控制器方法执行之后执行;请求处理完成之后执行);过滤器仅提供一个方法

  • 过滤器实现 Filter 接口,拦截器实现 HandlerInterceptor 接口

  • 过滤器过滤 servlet 请求响应,拦截器则是拦截普通类方法执行

转发和重定向:

转发是指服务器接收到用户请求后,将该请求发送到另一个 URL 地址,然后将该 URL 地址的响应返回给用户。转发是在服务器端完成的,用户并不知道请求已经被转发到了另一个地址。转发通常用于处理请求的过程中需要进行一些额外处理的情况,比如在处理请求前需要进行身份验证或者数据处理

重定向是指服务器接收到用户请求后,将该请求返回给用户一个新的 URL 地址,让用户再次发送请求到该地址。重定向是在客户端完成的,用户会在浏览器上看到地址被重定向到了另一个网页。重定向通常用于需要将用户请求转移到一个新的地址,比如网站的旧版网址已被废弃,需要将用户重定向到新的网址

总的来说,转发和重定向都是将用户请求转移到另一个 URL 地址的方式,只是实现方式和目的略有不同。在实际应用中,应根据具体情况选择转发和重定向的方式。

3、SpringMVC 内部处理请求流程

1、用户发起请求 doSome.do,请求被SpringMVC 前端控制器 DispatcherServlet捕获。

2、中央调度器 DispatcherServlet 接收用户的 doSome.do 请求,然后转发给处理器映射器。处理器映射器是指实现了 HandlerMapping 接口的类(可有多个),处理器映射器可根据用户请求,从 SpringMVC 容器中获取处理器类的对象(也就是 Spring 中的 getBean 方法),然后将获取到的处理器对象放入到处理器执行链(HandlerExecutionChain)中保存,这个类中,同时还保存了拦截器,保存形式为 List 集合。

3、DispatcherServlet 将处理器执行链 HandlerExecutionChain 中的处理器对象交给处理器适配器对象(可有多个)。处理器适配器指的是 SpringMVC 框架中实现了 HandlerAdapter 接口的类,用于执行处理器类中的处理器方法。

4、执行完处理器方法后,返回 ModelAndView,DispatcherServlet 将返回的 ModelAndView 交给视图解析器对象进行处理。视图解析器指的是实现了 ViewResoler 接口的类(可有多个),作用是根据 SpringMVC 配置文件中的视图解析器配置,使用前缀后缀创建 View 对象,View 对象是一个接口,用来表示视图,框架中 jsp、html 用 View 和其实现类来表示视图。

5、DispatcherServlet 获取第 4 步执行的结果 View,调用 View 类的方法,将 Model 数据添加到 request 作用域,执行对象视图的 forward 响应浏览器,请求结束。

spring总结_第2张图片

  1. 请求被SpringMVC 前端控制器 DispatcherServlet 捕获

  2. DispatcherServlet对请求URL进行解析(核心方法doDispatch()),得到请求资源标识符(URI)然后根据该URI,调用HandlerMapping获得该Handler(Controller)配置的所有相关的对象(包括Handler对象以及Handler对象对应的拦截器),最后以HandlerExecutionChain执行链对象的形式返回。

  3. DispatcherServlet 根据获得的Handler,选择一个合适的HandlerAdapter(执行目标方法的反射工具),如果成功获得HandlerAdapter,此时将开始执行拦截器的preHandler(…)方法【正向】

  4. 提取Request中的模型数据,填充Handler入参==(也就是给形参赋值)==,开始执行Handler(Controller)方法,处理请求。

    • 根据你的配置,Spring将帮你做一些额外的工作:

      a) HttpMessageConveter: 将请求消息(如Json、xml等数据)转换成一个对象,将对象转换为指定的响应信息

      b) 数据转换:对请求消息进行数据转换。如String转换成Integer、Double等

      c) 数据格式化:对请求消息进行数据格式化。 如将字符串转换成格式化数字或格式化日期等

      d) 数据验证: 验证数据的有效性(长度、格式等),验证结果存储到BindingResult或Error中

  5. Handler执行完成后,向DispatcherServlet 返回一个ModelAndView对象,==(1061行,mv=ha.handler)==此时将开始执行拦截器的postHandle(...)方法【逆向】。

  6. 根据返回的ModelAndView,选择一个适合的ViewResolver(视图解析器),==(有三种,redirect,forward和thymeleaf)==

  7. ViewResolver 结合Model和View,来渲染视图,渲染视图完毕执行拦截器的afterCompletion(…)方法【逆向】。

  8. DispatcherServlet 响应给客户端

4、什么是REST?

通俗来讲,就是通过URL就知道要什么资源,通过HTTP method就知道要干什么,通过HTTP status code就知道结果如何

使用REST有什么优势呢?

第一,风格统一了,不会出现delUser/deleteUser/removeUser各种命名的代码了。

第二,面向资源,一目了然,具有自解释性。

第三,充分利用 HTTP 协议本身语义

Spring MVC中的常用注解

5、@RestController

@RestController注解是@Controller和@ResponseBody的合集,表示这是个控制器 bean,并且是将函数的返回值直 接填入 HTTP 响应体中,是 REST 风格的控制器。

单独使用 @Controller 不加 @ResponseBody的话一般使用在要返回一个视图的情况,这种情况属于比较传统的 Spring MVC 的应用,对应于前后端不分离的情况。@Controller +@ResponseBody 返回 JSON 或 XML 形式数据

四、Mybatis

1、Mybatis和Hibernate的区别?

2、#{}和${}的区别

${}是 Properties 文件中的变量占位符,需要单引号

#{}是 sql 的参数占位符,#{ } 被解析成预编译语句,会将 sql 中的#{}替换为? ,预编译之后可以直接执行

sql注入:是一种注入攻击,它通过将任意代码插入数据库查询,使得攻击者完全控制数据库服务器。 使用#{}可以有效的防止SQL注入MyBatis启用了预编译功能,在SQL执行前,会先将上面的SQL发送给数据库进行编译;执行时,直接使用编译好的SQL,替换占位符“?”就可以了。因为SQL注入只能对编译过程起作用,所以这样的方式就很好地避免了SQL注入的问题。

3、二级缓存


MyBatis常见面试题总结


分页插件:

  • PageHelper:PageHelper 是一个 MyBatis 分页插件,在代码中使用 PageHelper.startPage() 方法来实现分页。

  • RowBounds:RowBounds 是 MyBatis 中定义的一个对象,用于指定查询结果的起始位置和数量,从而实现分页功能。它需要在查询方法中显式传递 RowBounds 对象,同时需要在 SQL 语句中使用 LIMIT 或 OFFSET 关键字来指定分页参数。

mybatis和mybatis-plus:使用 MyBatis-Plus 可以通过继承 BaseMapper 接口来自动生成常用的 CRUD 操作。

在使用MyBatis-Plus进行分页查询时,需要先创建一个Page对象,并将查询参数和分页参数设置到Page对象中,然后将Page对象传递给MyBatis的查询方法进行查询。

总的来说,MyBatis-Plus 在 MyBatis 的基础上提供了更多的功能和便利性,可以提高开发效率和代码质量。但是,如果需要更加灵活和自定义的 ORM(Object-Relational Mapping,即对象关系映射) 操作,MyBatis 可能更加适合。

恒生使用自家的querypage进行分页查询

    @Override
    public QueryPage getAllDealRequest(Integer pageNo, Integer pageSize) {
        String sqlList = "select r.id, r.environment, r.contact_person_name, u.username, r.employee_id,  r.deal_process, r.deal_duration, r.deal_status, r.deal_result" +
                " FROM repo_deal_request r LEFT JOIN repo_user u ON r.employee_id = u.employee_id "
                + " ORDER BY deal_status DESC limit ?,?";

        String sqlCount = "select count(*) from repo_deal_request ";

        UfBaseException exc = new UfBaseException(ErrorConsts.ERR_BASE_DAO);
        QueryPage queryPage = new QueryPage();
        queryPage.setCurrentPage(pageNo);
        queryPage.setTotal(this.jdbcTemplate.queryForObject(() -> exc, sqlCount, new Object[]{}, Integer.class));
        queryPage.setRows(this.jdbcTemplate.query(() -> exc, sqlList, new PreparedStatementSetter() {
            @Override
            public void setValues(PreparedStatement ps) throws SQLException {
                ps.setInt(1, (pageNo - 1) * pageSize);
                ps.setInt(2, pageSize);
            }
        }, new RowMapper() {
            @Override
            public Deal mapRow(ResultSet rs, int rowNum) throws SQLException {
                Deal deal = new Deal();
                deal.setId(rs.getInt(1));
                deal.setEnvironment(rs.getString(2));
                deal.setContactPersonName(rs.getString(3));
                deal.setUsername(rs.getString(4));
                deal.setEmployeeId(rs.getString(5));
                deal.setDealProcess(rs.getString(6));
                deal.setDuration(rs.getString(7));
                deal.setDealStatus(rs.getString(8));
                deal.setDealResult(rs.getString(9));
                return deal;
            }
        }));
        return queryPage;
    }

你可能感兴趣的:(面试,spring,java,后端)