Spring总结的question
Spring
一. 控制反转(IoC)
1.手动
使用了Spring的@Configuration
和@Bean
注解来明确指定了哪些类需要被纳入容器的管理。在AppConfig
配置类中,通过@Bean
注解创建了Service
和Controller
的实例,Spring会自动将这些实例纳入容器的管理,并处理它们之间的依赖关系。
// 定义一个Service接口
public interface Service {void doSomething();
}
// 实现Service接口的具体类
public class ServiceImpl implements Service {@Overridepublic void doSomething() {System.out.println("Service is doing something.");}
}
// 定义一个Controller类,它依赖于Service接口
public class Controller {dprivate Service service;// 通过构造函数注入依赖public Controller(Service service) {this.service = service;}public void doAction() {service.doSomething();}
}
// 在应用的入口处,使用Spring容器创建实例并进行依赖关系的管理
public class Main {public static void main(String[] args) {// 创建Spring容器ApplicationContext context = new AnnotationConfigApplicationContext(AppConfig.class);// 从容器中获取Controller实例Controller controller = context.getBean(Controller.class);// 调用Controller的方法,会自动调用Service的方法controller.doAction();}
}
// 定义一个配置类,用于告诉Spring容器如何创建和管理Bean
@Configuration
public class AppConfig {@Beanpublic Service service() {return new ServiceImpl();}@Beanpublic Controller controller(Service service) {return new Controller(service);}
}
2.自动
SpringApplication.run(CommunityApplication.class, args)
会扫描应用中的所有组件(包括被@Component
、@Service
、@Repository
等注解标记的类),并将它们纳入Spring容器的管理。通过调用SpringApplication.run
方法启动应用,会自动创建一个Spring应用上下文(ApplicationContext),并初始化整个应用的配置和组件。
public static void main(String[] args) {SpringApplication.run(CommunityApplication.class, args);}
@SpringBootApplication
实际上是一个组合注解,包含了@SpringBootConfiguration
、@EnableAutoConfiguration
和@ComponentScan
三个注解。其中,@SpringBootConfiguration
注解表示这是一个Spring Boot的配置类,@EnableAutoConfiguration
注解启用自动配置,@ComponentScan
注解指定要扫描的包路径。
使用Spring Boot的自动化机制可以方便快捷地扫描和管理所有的Bean,而手动进行依赖注入可以更加精确地控制容器中的Bean。
Q1:使用@Repository注解时,怎么在Spring的配置文件中进行相关的配置?
1、Spring
在使用@Repository注解时,可以在Spring的配置文件中进行相关的配置。以下是配置步骤:
- 在Spring的配置文件中添加
context:component-scan
标签,用于开启组件扫描功能,扫描带有@Repository
注解的类。示例如下:
<context:component-scan base-package="com.example.repository" />
其中,base-package
属性指定了要扫描的包路径。
- 如果需要配置数据源和事务管理器,可以在Spring的配置文件中进行相关的配置。示例如下:
<bean id="dataSource" class="org.apache.commons.dbcp2.BasicDataSource"><!-- 数据源相关配置 -->
</bean>
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager"><property name="dataSource" ref="dataSource" />
</bean>
其中,dataSource
是数据源的配置,transactionManager
是事务管理器的配置。
- 如果需要使用
@Repository
注解对应的数据访问异常转化功能,可以配置相关的异常转化器。示例如下:
<bean class="org.springframework.dao.annotation.PersistenceExceptionTranslationPostProcessor" />
这个配置会自动为带有@Repository
注解的类添加异常转化功能。
通过以上配置,就可以在Spring的配置文件中配置@Repository
注解相关的配置。注意,具体的配置内容根据实际需求和使用的技术选择可能会有所不同。
2、Spring Boot
在使用Spring Boot时,可以省略繁琐的配置过程,因为Spring Boot提供了自动配置的功能。对于@Repository注解的配置,可以按照以下步骤进行:
- 在Spring Boot主类上添加
@SpringBootApplication
注解,该注解包含了@EnableAutoConfiguration
注解,用于开启自动配置功能。 - 确保@Repository注解所在的包或子包在主类的扫描范围内,可以通过
@ComponentScan
注解进行配置,或者将主类放在包的顶层位置。 - 如果需要配置数据源,可以在
application.properties
或application.yml
配置文件中添加相关的配置项,如下所示:
propertiesCopy codespring.datasource.url=jdbc:mysql://localhost:3306/mydb
spring.datasource.username=root
spring.datasource.password=123456
spring.datasource.driver-class-name=com.mysql.jdbc.Driver
这样,Spring Boot会根据配置文件的内容自动配置数据源。
- 如果需要事务管理器,可以在需要使用事务的类或方法上添加
@Transactional
注解,Spring Boot会自动配置事务管理器。 通过以上步骤,就可以在Spring Boot中使用@Repository注解,无需进行繁琐的配置,Spring Boot会根据约定和自动配置的机制自动完成相关的配置。
Q2:@Primary有什么用
@Primary注解是Spring框架中的一个注解,用于标识主要的Bean实例。当存在多个同类型的Bean实例时,通过使用@Primary注解,可以指定其中一个Bean实例为首选的主要实例。
Q3:@Repository有什么用
@Repository注解是Spring框架中的一个注解,用于标识持久层组件(如DAO类)。
@Repository的作用主要有以下几点:
- 标识持久层组件:通过在持久层的类上添加
@Repository
注解,可以告诉Spring容器该类是一个用于数据访问的组件。Spring在进行组件扫描时,会扫描带有@Repository
注解的类,并将其实例化为Bean
。 - 提供异常转化功能:
@Repository
注解还提供了数据访问异常的转化机制。当数据访问过程中发生异常时,Spring会将底层的数据访问异常(如JDBC异常)转化为Spring的统一异常体系,使得应用程序可以更方便地处理和捕获异常。 - 具备@Component的功能:
@Repository
注解是@Component
注解的派生注解,因此@Repository
注解具备@Component
的所有功能。它可以被Spring容器自动扫描并装配,可以使用@Autowired
或@Resource
等注解进行依赖注入,也可以使用@Qualifier注解进行指定具体的实现类。
Q4:谈谈对IoC的理解
控制:创建、实例化对象的权力
反转:将这些权力交给IoC容器和Spring框架
将对象之间的依赖关系交给IoC容器管理,由IoC容器完成对象的注入,简化开发,IoC容器像是一个工厂,创建一个对象时只配置好,不需要考虑怎么被创建出来的。Spring中用Xml文件配置bean,在Spring Boot中用注解配置。
Q5:@Component和@Bean的区别
-
@Component注解作用于类,而@Bean注解作用于方法
-
@Component通常是通过类路径扫描来自动侦察以及自动装配到Spring容器中;@Bean在标有该注解的方法中定义产生这个bean,@Bean告诉了Spring这是某个类的实例,当我需要的时候还给我。
-
@Bean比@Component的自定义性更强
Q6:注入Bean的注解
- @Autowired
- @Resource
- @Inject
Q7:@Autowired和@Resource的区别
-
@Autowired
属于Spring
内置的注解,默认的注入方式是byType(根据类型进行匹配)
,首先根据接口类型去匹配并注入Bean
。如果一个接口有多个实现类,注入方式就会变为byName(根据名称匹配)
举个例子,
SmsService
接口有两个实现类:SmsServiceImpl1
和SmsServiceImpl2
,且它们都已经被Spring
容器所管理。
// 报错,byName 和 byType 都无法匹配到 bean
@Autowired
private SmsService smsService;
// 正确注入 SmsServiceImpl1 对象对应的 bean
@Autowired
private SmsService smsServiceImpl1;
// 正确注入 SmsServiceImpl1 对象对应的 bean
// smsServiceImpl1 就是我们上面所说的名称
@Autowired
@Qualifier(value = "smsServiceImpl1")
private SmsService smsService;
@Resource
属于 JDK 提供的注解,默认注入方式为byName
。如果无法通过名称匹配到对应的 Bean 的话,注入方式会变为byType
。
@Resource
有两个比较重要且日常开发常用的属性:name
(名称)、type
(类型)。
public @interface Resource {String name() default "";Class<?> type() default Object.class;
}
如果仅指定 name
属性则注入方式为byName
,如果仅指定type
属性则注入方式为byType
,如果同时指定name
和type
属性(不建议这么做)则注入方式为byType
+byName
。
// 报错,byName 和 byType 都无法匹配到 bean
@Resource
private SmsService smsService;
// 正确注入 SmsServiceImpl1 对象对应的 bean
@Resource
private SmsService smsServiceImpl1;
// 正确注入 SmsServiceImpl1 对象对应的 bean(比较推荐这种方式)
@Resource(name = "smsServiceImpl1")
private SmsService smsService;
总结一下:
@Autowired
是 Spring 提供的注解,@Resource
是 JDK 提供的注解。Autowired
默认的注入方式为byType
(根据类型进行匹配),@Resource
默认注入方式为byName
(根据名称进行匹配)。- 当一个接口存在多个实现类的情况下,
@Autowired
和@Resource
都需要通过名称才能正确匹配到对应的 Bean。Autowired
可以通过@Qualifier
注解来显式指定名称,@Resource
可以通过name
属性来显式指定名称。 @Autowired
支持在构造函数、方法、字段和参数上使用。@Resource
主要用于字段和方法上的注入,不支持在构造函数或参数上使用
Q8:Bean的作用域
- Singleton:IoC容器中只有唯一的bean实例,Spring的bean默认都是单例的。在之后的每次请求或注入时,都会返回同一个实例,而不会重新创建新的实例。
- prototype:每次获取都会创建一个新的 bean 实例。与默认的单例模式不同,每次通过容器获取prototype作用域的Bean时,都会创建一个新的实例。原型模式的Bean不适合进行依赖注入,因为每次注入都会得到一个新的实例,无法保证依赖关系的一致性。
- request (仅 Web 应用可用): 每一次 HTTP 请求都会产生一个新的 bean(请求 bean),该 bean 仅在当前 HTTP request 内有效。
- session (仅 Web 应用可用) : 每一次来自新 session 的 HTTP 请求都会产生一个新的 bean(会话 bean),该 bean 仅在当前 HTTP session 内有效。
Q9:为什么在Spring boot没有配置 bean 的作用域
在Spring Boot中,为了简化配置和提高开发效率,通常不需要显式地配置Bean的作用域。Spring Boot默认使用单例模式来管理Bean,即每个Bean在容器中只会存在一个实例。 这是因为Spring Boot遵循"约定优于配置"的原则,通过自动配置和默认配置来简化开发过程。在大多数情况下,单例模式已经能够满足开发需求,因此默认使用单例模式可以减少不必要的配置。 如果需要使用其他作用域,如原型(prototype)、会话(session)、请求(request)等,可以在需要的地方使用特定的注解来标记,而不需要在配置文件中显式配置。例如,可以使用**@Scope("prototype")
**注解来将特定的Bean定义为原型模式。
二. 面向切面编程(AOP)
术语 | 含义 |
---|---|
目标(Target) | 目标对象/被通知的对象 |
代理(Proxy) | 向目标对象应用通知之后创建的代理对象 |
连接点(JoinPoint) | 目标对象的所属类中,定义的所有方法均为连接点 |
切入点(Pointcut) | 被切面拦截/增强的连接点(切入点一定是连接点,连接点不一定是织入点) |
通知(Advice) | 增强的逻辑/代码,也是拦截到目标对象的连接点后应该做的事 |
织入(Weaving) | 将通知 应用到目标对象,产生代理对象的过程动作 |
方面主键(Aspect) | Pointcut+Advice |
Q1:谈谈对AOP的理解
能够将与业务无关,却为业务模块所共同调用的逻辑和责任所封装起来,例如:事务处理、权限控制,日志管理,减少重复代码,比较好维护。
Spring AOP
基于动态代理的,如果代理的对象实现了某个接口,那么Spring AOP
会使用JDK Proxy
,去创建代理对象;而对于没有实现接口的对象,Spring AOP
使用Cglib
生成一个被代理对象的子类作为代理。
Spring AOP
的工作原理:自动为目标对象生成代理,并在方法调用时织入切面逻辑。
代理对象是通过Spring AOP
自动生成的,并且已经被注入到ApplicationContext
中。具体来说,代理对象是在以下代码中获取的:
UserService userService = context.getBean(UserService.class);
// 主类
@SpringBootApplication
public class Application {public static void main(String[] args) {ApplicationContext context = SpringApplication.run(Application.class, args);UserService userService = context.getBean(UserService.class);userService.addUser("john", "123456");}
}
在这个示例中,通过ApplicationContext
的getBean
方法来获取代理对象。根据Spring AOP
的配置,如果UserService
接口被代理,那么获取到的userService
对象就是代理对象;如果UserServiceImpl
类被代理,那么获取到的userService
对象也是代理对象。
Q2:为什么要对Spring AOP进行代理,不代理会怎样?
在Spring AOP
中,代理是实现切面功能的关键。如果不进行代理,切面逻辑将无法被织入到目标对象的方法调用中,失去了AOP
的作用。 具体来说,代理对象在目标对象和调用方之间充当了一个中间层。当调用方调用代理对象的方法时,代理对象会在方法执行前后执行切面逻辑。这样,我们可以在切面中添加一些额外的逻辑,比如日志记录、事务管理、性能监控等。代理对象将切面逻辑织入到目标对象的方法调用中,从而实现了横切关注点的模块化。 如果不进行代理,切面逻辑将无法被自动应用到目标对象的方法调用中。这意味着我们需要在每个目标对象方法的调用处手动添加切面逻辑,这样会导致代码的重复和冗余,不利于代码的维护和扩展。而代理机制可以自动为目标对象生成代理,并在方法调用时织入切面逻辑,使得切面的应用更加便捷和灵活。 除了将切面逻辑织入到方法调用中,代理还可以实现其他功能,比如延迟加载、事务管理、缓存等。代理对象可以拦截方法调用,根据需要进行一些额外的处理,从而提供更多的功能。
Q3:那在以下代码中,谁是目标对象,谁是代理对象,谁是调用方?
public class AlphaAspect { @Pointcut("execution(* com.newcoder.community.service.*.*(..))")//所有类、所有方法
public void pointcut(){}
@Before("pointcut()")//连接点开始记日志
public void before(){System.out.println("before");
}@After("pointcut()")//连接点后记日志
public void after(){System.out.println("after");
}@AfterReturning("pointcut()")//有返回值后记日志
public void afterReturn(){System.out.println("afterReturn");
}@AfterThrowing("pointcut()")//抛异常后记日志
public void afterThrowing(){System.out.println("afterThrowing");
}@Around("pointcut()")//前后都织入 执行代理对象,织入代理对象,用来代替原始对象
public Object around(ProceedingJoinPoint joinPoint) throws Throwable{//ProceedingJoinPoint为连接点,织入部位System.out.println("around before");Object obj = joinPoint.proceed();//proceed调目标主键 调用原始对象方法System.out.println("around after");return obj;
}
在这个例子中,目标对象是com.newcoder.community.service包下的所有类的所有方法。 AlphaAspect类本身是一个切面类,其中包含了各种注解标记的通知方法。这些通知方法会在目标对象的方法调用前后执行相应的逻辑。因此,AlphaAspect类是代理对象。 调用方是在业务代码中调用目标对象的方法的地方,这个例子中没有给出具体的业务代码,所以无法确定调用方是什么。
所以,代理对象会在目标对象的方法调用前后执行相应的逻辑。
Q4:那为什么说向目标对象应用通知之后创建代理对象?
在AOP中,通知(Advice)是切面的核心逻辑,用于在目标对象的方法调用前后执行特定的操作。为了将通知应用到目标对象的方法调用中,需要创建代理对象来包装目标对象。代理对象负责拦截目标对象的方法调用,并在适当的时机执行通知。 代理对象的创建过程可以分为两种方式:静态代理和动态代理。
- 静态代理:在编译时就已经将切面逻辑与目标对象织入到了一起,生成了代理类的字节码文件。代理对象是在编译时生成的,不需要在运行时再去创建。(AspectJ)
- 动态代理:在运行时动态地生成代理对象。动态代理需要借助于Java的反射机制来实现。通过动态创建代理对象,可以根据切面的配置在运行时将通知应用到目标对象的方法调用中。 在Spring AOP中,默认使用的是动态代理。Spring使用JDK动态代理和CGLIB动态代理两种方式来创建代理对象。如果目标对象实现了接口,则使用JDK动态代理;如果目标对象没有实现接口,则使用CGLIB动态代理。 无论是静态代理还是动态代理,代理对象的创建都是在应用通知之后进行的。通过代理对象,切面逻辑可以被织入到目标对象的方法调用中,实现对目标对象的增强。
Q5:目标对象所有的方法就是连接点吗?
是的,目标对象的所有方法都可以作为连接点。连接点是程序执行过程中的特定点,包括方法的调用、异常的抛出、字段的访问等。在AOP中,最常见的连接点是方法的调用,因为我们通常希望在方法的执行前、执行后或发生异常时插入切面逻辑。 在AOP中,可以选择在目标对象的所有方法上织入切面逻辑,也可以选择只在特定的方法上织入切面逻辑,这取决于所定义的切点(Pointcut)。切点是定义在哪些连接点上织入切面逻辑的规则,可以使用表达式或注解来定义切点。
Q6:切入点是类路径吗?
不,切入点(Pointcut)并不是类路径。切入点是在AOP
中用于定义哪些连接点(JoinPoint)应该被织入切面逻辑的规则。 切入点可以使用表达式或注解来定义。使用表达式定义切入点时,可以使用AspectJ
风格的切入点表达式,如execution、within、args
等关键字,以及类、方法、参数等信息来描述需要织入切面逻辑的连接点。使用注解来定义切入点时,可以通过在目标对象的方法上添加特定的注解,然后通过切入点表达式来匹配这些注解来确定要织入切面逻辑的连接点。 切入点可以非常灵活地定义,可以选择在目标对象的所有方法上织入切面逻辑,也可以选择只在特定的方法或类上织入切面逻辑。切入点的定义是根据业务需求和设计目标来确定的,通常会根据实际情况来选择需要织入切面逻辑的连接点。
Q7:织入的过程是不是就相当于动态代理和静态代理过程?
是的,织入的过程可以类比为动态代理和静态代理的过程。
在静态代理中,代理对象和目标对象实现同一个接口,代理对象在调用目标对象方法的前后插入额外的逻辑。这种方式需要在编译时期就确定代理关系,并在代码中显式地指定代理对象。
在动态代理中,代理对象是在运行时动态生成的,无需事先编写代理类。通过Java的反射机制,动态代理可以在运行时拦截并处理目标对象的方法调用。在动态代理中,我们可以在目标对象方法的调用前后插入切面逻辑。
类似地,AOP
的织入过程也是在运行时动态生成的。AOP
框架会根据切入点的定义,对目标对象的方法调用进行拦截,并根据切面逻辑对其进行增强。这个过程可以看作是在运行时动态代理的过程。 不同的是,动态代理和静态代理通常是针对单个类或对象进行的,而**AOP
的织入可以同时作用于多个类和对象**,根据切入点的定义对满足条件的连接点进行增强。
三、Spring MVC
Q1:说说自己对Spring MVC的了解
MVC是模型(Model)、视图(View)、控制器(Controller)的简写,它是通过将业务逻辑、数据、显示分离组织代码。
Q2:Spring MVC的核心组件有哪些?
DispatcherServlet
:核心的中央处理器,负责接受请求、分发,并给予客户响应HandlerMapping
:处理器映射器,根据URL去匹配查找能处理的Handler
,并会将请求涉及到的拦截器和Handler
一起封装HandlerAdapter
:处理器适配器 ,根据HandlerMapping
找到的Handler
,适配执行对应的Handler
.Handler
:请求处理器,处理实际请求的处理器ViewResolver
:视图解析器,根据Handler
返回的逻辑视图,解析并渲染真正的视图,并传递给DispatcherServlet响应客户端
Q3:Spring MVC的工作原理
- 客户端发送请求,
DispatcherServlet
拦截请求 DispatcherServlet
根据请求信息调用HandlerMapping
。HandlerMapping
根据URL去匹配查找能处理的Handler
,并会将涉及到的拦截器和Handler
一起封装DispatcherServlet
调用HandlerAdapter
适配器执行Handler
Handler
完成对用户的请求的处理,返回一个ModelAndView
对象给DispatcherServlet
ViewResolver
根据逻辑View
查找实际的View
DispatcherServlet
把返回的Model
传给View
View
返回客户端
Q4:Handler 是什么?
Handler 是指在 Spring MVC 框架中用于处理用户请求的组件。Handler 可以是一个 Controller 类中的方法、一个 Servlet、一个 WebSocket 处理器或其他可处理请求的组件。
Q5:DispatcherServlet 为什么调用 HandlerAdapter适配器执行 Handler?
不同的 Handler 可能有不同的处理方式,例如一个 Controller 方法、一个 Servlet、一个 WebSocket 处理器等。为了统一处理不同类型的 Handler,需要使用适配器模式将不同类型的 Handler 适配为统一的处理方式。 HandlerAdapter 适配器的作用就是根据不同类型的 Handler,将请求信息进行适配,使其能够被统一调用并执行。它根据 Handler 的类型,调用相应的适配方法,将请求信息传递给 Handler 进行处理,并获取处理结果返回给 DispatcherServlet。 通过使用 HandlerAdapter 适配器,DispatcherServlet 不需要关心具体的 Handler 类型,只需要调用适配器的方法即可,实现了对不同类型 Handler 的统一调用和处理。
Q5:为什么会将请求涉及到的拦截器和 Handler 一起封装?
将请求涉及到的拦截器和Handler一起封装的目的是为了在请求处理过程中能够方便地对请求进行拦截和处理。 拦截器是用于对请求进行预处理和后处理的组件,可以在请求到达Controller之前和之后执行额外的逻辑。通过将拦截器和Handler一起封装,可以实现以下几个方面的功能:
- 统一管理拦截器:将拦截器和Handler一起封装,可以方便地统一管理拦截器的配置和使用。在配置文件或注解中指定拦截器的顺序和范围,可以灵活地控制拦截器的执行顺序和作用范围。
- 方便拦截器的调用:将拦截器和Handler一起封装后,可以在请求到达Controller之前和之后分别调用拦截器的预处理和后处理方法。这样可以方便地对请求进行拦截和处理,执行一些通用的操作,如权限验证、日志记录等。
- 提高代码的复用性:将一些通用的逻辑处理抽离出来作为拦截器,通过封装拦截器和Handler,可以在多个请求处理过程中共享这些逻辑,提高代码的复用性。例如,多个请求需要进行权限验证,可以将权限验证的逻辑抽象为一个拦截器,在多个请求处理过程中共享使用。
- 灵活控制请求处理流程:通过封装拦截器和Handler,可以灵活控制请求处理流程。在拦截器的预处理方法中,可以决定是否继续处理请求,或者进行一些重定向或错误处理操作。在拦截器的后处理方法中,可以对响应结果进行进一步的处理或修改。
四、设计模式
Q1:Spring框架中用到了哪些设计模式?
- 工厂模式:通过beanFactory、ApplicationContext创建bean对象
- 代理模式:Spring AOP功能的实现
- 单例模式:Spring的bean默认都是单例的
- 适配器模式:Spring MVC用到了适配器模式适配handler、Spring AOP的Advice用到了适配器模式适配成MethodInterceptor接口类型的对象(全都变成方法拦截器对象)
- 模板模式:以Template结尾的对数据库操作的类
- 包装器模式:项目需要连接多个数据库,不同的客户每次访问可能会访问不同的数据库。包装器模式可动态的切换不同数据源。
五、Spring事务
Q1:事务的特性(ACID)了解吗?
- 原子性:事务是最小的执行单位,不允许分割,事物的原子性确保动作要么全部完成,要么不起作用
- 一致性:执行事务前后,数据保持一致,例如转账时,无论事务是否成功,转账人和收款人的总额应该是不变的
- 隔离性:并发访问数据库时,一个用户的事务不被其他事务所干扰,各并发事务之间的数据库是独立的
- 持久性:一个事务被提交以后,他对数据库的改变是持久的,数据库发生故障也不应该对它有任何影响
只有保证了原子性、隔离性、持久性以后,一致性才能得到保障:AID->C
Q2:什么时候才用事务的隔离性?
事务的隔离性是指多个事务并发执行时,各个事务之间的数据应该是相互隔离的,一个事务的操作不应该对其他事务的操作产生影响。在并发环境下,如果多个事务同时访问和修改共享数据,可能会导致数据不一致的问题。 举个例子来说明事务的隔离性的使用场景: 假设有一个电商平台,用户可以在平台上购买商品,而商品的库存是需要管理的。当用户购买商品时,会进行库存的扣减操作。在这个场景中,如果不考虑事务的隔离性,可能会出现以下问题:
- 非隔离性导致的库存错误:假设有两个用户 A 和 B 同时购买同一件商品,且库存只有一件。如果不使用事务的隔离性,A 和 B 同时发起购买请求时,在没有互斥控制的情况下,可能会导致库存扣减错误。例如,A 和 B 同时读取库存数量为 1,然后都进行库存扣减,最终库存可能会变成 -1。 为了解决这个问题,可以使用事务的隔离性。通过将库存扣减操作放在一个事务中,并使用合适的隔离级别,可以避免并发访问时的数据不一致问题。例如,使用数据库的隔离级别 SERIALIZABLE,可以确保同一时间只有一个事务能够访问和修改库存数据,从而避免库存错误问题。
Q3:MySQL怎么保证原子性?
保证原子性,就要在异常发生的时候对已经执行的操作进行回滚,在MySQL中,恢复机制是通过回滚日志实现的,所有事务进行的修改都会先记录到这个回滚日志中,然后再执行相关的操作。如果执行过程中出现异常,就利用回滚日志中的信息将数据回滚到修改之前的样子。并且,回滚日志会先把数据持久化到硬盘上,这样就能保证数据库在事务执行过程中宕机,未完成的事务会自动回滚。当再次打开数据库时,数据库会通过回滚日志来查找未完成的事务,并对其进行回滚操作,以保证数据的一致性。
未待完续。。。
相关文章:
Spring总结的question
Spring 一. 控制反转(IoC) 1.手动 使用了Spring的Configuration和Bean注解来明确指定了哪些类需要被纳入容器的管理。在AppConfig配置类中,通过Bean注解创建了Service和Controller的实例,Spring会自动将这些实例纳入容器的管理,并处理它们…...
LVS和keepalived
Keepalived及其工作原理 Keepalived 是一个基于VRRP协议来实现的LVS服务高可用方案,可以解决静态路由出现的单点故障问题。 在一个LVS服务集群中通常有主服务器(MASTER)和备份服务器(BACKUP)两种角色的服务器&#x…...
2023年腾讯云优惠券(代金券)无门槛领取方法汇总
腾讯云作为国内知名的云计算服务提供商,为了吸引用户,腾讯云经常推出各种优惠活动,其中包括优惠券的免费发放。通过使用优惠券,可以享受到更多的折扣和优惠,节省成本,获得更好的用户体验。那么,…...
linux scsi命令读取文件
SCSI Read(10)是一种用于从SCSI设备读取数据的命令。下面是一个简单的示例代码,演示如何使用SCSI Read(10)命令来读取指定大小的文件: #include <stdio.h> #include <stdlib.h> #include <string.h>#define READ_CAPACITY_CMD 0x2…...
c#设计模式-行为型模式 之 策略模式
🚀简介 🐤作为一个开发人员,开发需要选择一款开发工具,如在编写C#时,我们可以选择VisualStudio进行开发,也可以使用Rider 进行开发。 🐳该模式定义了一系列算法,并将每个算法封装起来…...
【拿完年终奖后】想要转行网络安全,一定不要错过这个时间段。
网络安全,作为当下互联网行业中较为热门的岗位,薪资可观、人才需求量大,作为转行必考虑。 在这里奉劝所有零基础想转行(入门) 网络安全的朋友们 在转行之前,一定要对网络安全行业做一个大概了解…...
day10_复习_数组_方法
非常重要的: 方法设计(参数,返回值,调用) 数组也重要,但是后续很少用! 是因为后期有更简单的【集合】,重要在于是一种思想,也是一种代码逻辑 关于数组: 声明创建取值,存值遍历面试|算法 --> 排序内存图(堆,栈,引用) 今天 数组工具类:Arrays数组扩容(拷…...
Linux:TCP三握四挥简析
文章目录 1. 前言2. 背景3. TCP连接的建立和断开3.1 TCP协议状态机3.2 TCP的三握四挥3.2.1 TCP 连接建立的三次握手过程分析3.2.1.1 服务端和客户端套接字的创建3.2.1.2 服务端进入 LISTEN 状态3.2.1.3 服务端在 LISTEN 状态等待客户端的 SYN 请求3.2.1.4 客户端向服务端发送 S…...
2023年全球市场数字干膜测量仪总体规模、主要生产商、主要地区、产品和应用细分研究报告
内容摘要 按收入计,2022年全球数字干膜测量仪收入大约149.2百万美元,预计2029年达到191.6百万美元,2023至2029期间,年复合增长率CAGR为 3.6%。同时2022年全球数字干膜测量仪销量大约 ,预计2029年将达到 。2022年中国市…...
Python爬虫脚本的基本组成
一个基本的Python爬虫脚本通常由以下几部分组成: 导入必要的库:Python中有许多库可用于爬虫,如requests用于发送HTTP请求,BeautifulSoup用于解析HTML或XML,selenium用于模拟浏览器操作等。你需要根据你的需求导入相应…...
IIS部署Flask
启用 CGI 安装wfastcgi pip install wfastcgi 启用 wfastcgi 首先以管理员身份运行wfastcgi-enable来在IIS上启用wfastcgi,这个命令位于c:\python_dir\scripts,也就是你需要确保此目录在系统的PATH里,或者你需要cd到这个目录后再执行。 #…...
告警繁杂迷人眼,多源分析见月明
随着数字化浪潮的蓬勃兴起,网络安全问题日趋凸显,面对指数级增长的威胁和告警,传统的安全防御往往力不从心。网内业务逻辑不规范、安全设备技术不成熟都会导致安全设备触发告警。如何在海量众多安全告警中识别出真正的网络安全攻击事件成为安…...
【Python】概述
【Python】概述 特点 Python 是一种面向对象、解释性、弱类型(动态数据类型)的脚本语言(高级程序设计语言)。 由于Python是解释型语言,所以具有跨平台特性。 解释型语言: 这意味着开发过程中没有了编译…...
MySQL运维之日志管理
目录 一、日志 1.1错误日志 1.2二进制日志 1.2.1格式 1.2.2查看 1.2.3删除 1.3查询日志...
Yolov5 ONNX导出报错: export failure: Unsupported ONNX opset version: 17
目录 1.问题描述 1.1 报错1 : 1.2 报错 2 2.解决方案 介绍 ONNX(Open Neural Network Exchange)是一个用于机器学习模型的开放式标准,它旨在使不同的深度学习框架能够将训练好的模型在不同平台上无缝运行。它是由Microsoft和F…...
2023年全球市场儿科PICC导管总体规模、主要生产商、主要地区、产品和应用细分研究报告
内容摘要 按收入计,2022年全球儿科PICC导管收入大约 百万美元,预计2029年达到 百万美元,2023至2029期间,年复合增长率CAGR为 %。同时2022年全球儿科PICC导管销量大约 ,预计2029年将达到 。2022年中国市场规模大约为 百…...
Adler-32算法使用Neon优化
1、简单实现 下面代码是Adler-32算法的简单实现,我们来整理一下这段代码的逻辑: A = 1 + D1 + D2 + ... + Dn (mod 65521)B = (1 + D1) + (1 + D1 + D2) + ... + (1 + D1 + D2 + ... + Dn) (mod 65521)= nxD1 + (n-1) x D2 + (n-2) x D3 + ... + Dn + n (mod 65521)Adler-3…...
数据结构-----平衡二叉树
目录 前言 1.平衡二叉树 1.1概念与特点 1.2与二叉排序树比较 1.3判断平衡二叉树 2.平衡二叉树的构建 2.1平衡因子 BF 2.2 LL型失衡(右旋) 2.3 RR型失衡(左旋) 2.4 LR型失衡(先左旋再右旋) 2.5 RL…...
vue3 keepalive翻页保存页面状态
描述 实现页面 A-> B , B->A(A保存之前页面状态,不刷新页面) // router/index.tsimport { createRouter, createWebHistory } from vue-router import HomeView from ../views/HomeView.vueconst router createRouter({h…...
测试工程师思维学习
一、测试工程师应具备什么思维? 透过现象看本质,拒绝“一叶障目” 01、质疑和系统思维 02、创新思维 03、全局思维 04、风险驱动和组合思维 05、用户为中心和比较思维 06、BT思维和架构扩展性思维 二、测试工程师应避免的思维 01、同化现象 02、定位效…...
前端JavaScript入门到精通,javascript核心进阶ES6语法、API、js高级等基础知识和实战 —— Web APIs(六)
思维导图 一、正则表达式 1.1正则表达式介绍 1.2 语法 <!DOCTYPE html> <html lang"en"><head><meta charset"UTF-8"><meta http-equiv"X-UA-Compatible" content"IEedge"><meta name"viewpor…...
云硬盘和物理硬盘的区别
服务器的硬盘是服务器用来存储数据,一般有云硬盘和物理硬盘两种。云硬盘是云计算平台的虚拟技术的存储服务,将数据存储于云端通过分布式存储架构的形式。物理硬盘是将数据存储在服务器或者是PC端上,存储空间比较大,读写速度也很快…...
数据分析--观察数据处理异常值
引包: import pandas as pd import numpy as np 读取文件: dfpd.read_csv(./HR.csv) 文件见绑定资源(来自kaggle的HR.csv) 处理过程: 一、从df中拿出处理对象 二、找出缺失值的位置并删除 s1_sdf[satisfactio…...
vue3+elementPlus el-input的type=“number“时去除右边的上下箭头
改成 代码如下 <script lang"ts" setup> import {ref} from vue const inputBtn ref() </script> <template><el-input type"number" v-model"inputBtn" style"width: 80px;" class"no_number">…...
华为云云耀云服务器L实例评测|Elasticsearch的可视化Kibana工具安装 IK分词器的安装和使用
前言 最近华为云云耀云服务器L实例上新,也搞了一台来玩,期间遇到各种问题,在解决问题的过程中学到不少和运维相关的知识。 本篇博客介绍Elasticsearch的可视化Kibana工具安装,以及IK分词器的安装和使用。 其他相关的Elasticsea…...
加密货币交易技巧——人和(一)
交易原则 本篇主要讲述加密货币交易人需要注意的几个原则。 1.不能贪心,具体表现在做好仓位管理。第一,不要重仓进去,一定要轻仓。第二,开仓就想好本次要赚多少钱,不要太贪,到了预期点就止盈。第三&am…...
数学建模:最优化问题及其求解概述
数学建模:最优化问题及其求解概述 最优化问题定义分类离散优化问题连续优化问题 求解 此博客围绕运筹学以及最优化理论的相关知识,通俗易懂地介绍了最优化问题的定义、分类以及求解算法。 最优化问题 定义 数学优化(Mathematical Optimiza…...
企业办理CS资质,怎么选择办理等级?
信息系统建设和服务能力等级证书(Information system construction and service—Capability assessment system,简称:CS),由中国电子信息行业联合会组织开展的第三方评估活动,是根据《信息系统建设和服务能…...
华为云云耀云服务器L实例评测|Huawei Cloud EulerOS 自动化环境部署
[toc] Huawei Cloud EulerOS 自动化环境部署 云耀云服务器L实例【Huawei Cloud EulerOS 2.0 64bit】 Python Git Google Chrome Chromedriver Selenium More… 1. Python 镜像创建后自带。 2.Git 拉取项目。 sudo yum install git3. Google Chrome 使用root权限或sudo权…...
从一张表格开始做挖机报价系统
一、前言 历时4个月的挖机销售报价系统进入收尾阶段,由我直接负责与业务方对接,这中间各种折腾真是一言难尽,项目开发过程中还要维护POS系统以及牛奶配送系统,本项目我们采用的是迭代开发,今天讲一下具体的开发过程以…...
做网站公司青岛/app制作
其实用python的人应该都是不关注它性能的人,毕竟写python确实很愉快 PHP的核心维护者花了很多的心血却提高底层的解释器效率,为什么Python的维护者不去呢? 程序员都喜欢用数据说话,这里我用的python版本是Python 3.6.2(64位)&…...
制作销售网站有哪些问题/app如何推广以及推广渠道
JS数组array常用方法 1.检测数组 1)检测对象是否为数组,使用instanceof 操作符 if(value instanceof Array) { //对数组执行某些操作 } 2)获取对象的类型,比较是否为object类型(此方法只能检测是否为Object,不推荐) if(typeof(value)"Object") { //对数组执行某些操作…...
网站推广优化方法/海外网站cdn加速
关于grid的分页方式我个人理解有两种,我只针对对数据库表或视图的操作思路做一些讲解。 第一种是通过json类的调用,使查询出来的数据格式化,然后传回grid所在页面。在这种方法下,需要.net framework 2.0以上框架和一个json类的支…...
建设彩票网站多少钱/长沙网站搭建优化
一、修改端口号 spring-boot 默认的端口号是8080,如需修改。 1、新建一个src/main/resources 文件夹 2、在这个文件夹下新建一个application.propertise 文件 3、在这个文件里写 server.port 80 4、注意 要使用spring-boot:run启动。 配置文件名称必须为applicatio…...
网站 字号 英文/seo网站营销推广
一、背景 USB转PHY RTL8153不支持高通IPA硬加速,所以采用SFE软加速 调试设备为基于Cat.6通信模组的整机 SFE软加速前:UXM环境实际测速100Mbps,设备内部sirq 87% 二、SFE软加速驱动调测 SFE驱动代码路径:sdx12-ap\shortcut-fe\shortcut-fe SFE驱动编译文件路径:sdx12-a…...
公司做影视网站侵权/百度seo霸屏软件
原标题:iOS便签如何实现扫描二维码界面功能这是一款多功能便签软件工具,有“二维码”功能:它支持用户将便签内容制作成二维码,然后通过敬业签app扫描该二维码,显示相应的便签内容。那么,如何扫描便签二维码…...