4. 面向切面编程(AOP):
AOP的基本概念。
AOP(Aspect-Oriented Programming,面向切面编程)是一种编程范式,旨在通过切面(Aspect)将横切关注点与核心业务逻辑分离,以提高代码的模块化性、可维护性和可重用性。AOP 的核心思想是将横切关注点封装成切面,然后在程序的执行过程中,通过横切关注点的方式,将切面织入到核心业务逻辑中。
以下是 AOP 的一些基本概念:
-
切面(Aspect): 切面是横切关注点的模块化单元。它包含了横切关注点的定义以及在何时、何地执行这些关注点的信息。切面通常以面向对象编程的方式实现,它可以包括通知(Advice)和切点(Pointcut)。
-
通知(Advice): 通知是切面的一部分,它定义了在何时、何地执行横切关注点的具体逻辑。通知有多种类型,包括前置通知(Before Advice)、后置通知(After Advice)、返回通知(After Returning Advice)、异常通知(After Throwing Advice)和环绕通知(Around Advice)。
-
切点(Pointcut): 切点定义了在哪里执行横切关注点。它指定了在程序中的哪些位置应用通知,通常使用表达式或规则来匹配目标方法。
-
连接点(Join Point): 连接点是程序执行过程中可以插入切面的点。在 AOP 中,连接点通常是方法的调用或异常的抛出。
-
织入(Weaving): 织入是将切面插入到程序的执行流程中的过程。它可以在编译时、类加载时、运行时进行,AOP 框架负责执行织入操作。
-
引入(Introduction): 引入允许在不修改现有类代码的情况下,向现有类添加新的方法或属性。这使得在不影响原有代码的情况下,可以在运行时为类引入新的行为。
-
增强(Advice): 增强是通知和切点的组合,定义了横切关注点的逻辑以及在何时、何地执行。
AOP 的主要目标是提高代码的可维护性和可重用性,通过将横切关注点分离出来,可以更清晰地组织和管理代码。典型的应用场景包括日志记录、事务管理、性能监控等。常见的 AOP 框架有 Spring AOP、AspectJ 等。
切面、连接点、切入点和通知的含义。
在AOP(Aspect-Oriented Programming)中,有一些关键概念,包括切面、连接点、切入点和通知。让我们逐一解释这些概念的含义:
-
切面(Aspect):
- 含义: 切面是横切关注点的模块化单元。它定义了在何时、何地执行横切关注点的逻辑。切面通常包括切点和通知。
- 作用: 切面将横切关注点封装起来,提高了代码的模块化性和可维护性。
-
连接点(Join Point):
- 含义: 连接点是程序执行过程中可以插入切面的点。通常,连接点是方法的调用或异常的抛出。
- 作用: 切面可以在连接点上执行通知,以实现横切关注点的逻辑。
-
切入点(Pointcut):
- 含义: 切入点定义了在哪里执行横切关注点。它指定了在程序中的哪些位置应用通知,通常使用表达式或规则来匹配目标方法。
- 作用: 切入点帮助确定在哪些连接点上应用通知,它是切面中一个非常重要的部分。
-
通知(Advice):
- 含义: 通知是切面的一部分,它定义了在何时、何地执行横切关注点的具体逻辑。通知有多种类型,包括前置通知、后置通知、返回通知、异常通知和环绕通知。
- 作用: 通知实际上包含了横切关注点的逻辑,它在连接点上执行,将切面的行为插入到目标方法的执行流程中。
综合起来,切面通过连接点确定在程序执行的哪些位置应用通知,切入点定义了这些位置,通知定义了具体的逻辑。这些概念协同工作,使得在 AOP 中能够更好地实现关注点的分离和模块化。 Spring AOP 是一个常用的 AOP 框架,它通过这些概念来实现横切关注点的管理和执行。
在Spring中如何声明和使用切面。
在Spring中,声明和使用切面主要涉及以下几个步骤:
- 定义切面类:
- 创建一个类,并使用
@Aspect
注解来标识它为一个切面。 - 在切面类中定义通知(Advice)方法,用于指定横切关注点的逻辑。
- 创建一个类,并使用
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.springframework.stereotype.Component;@Aspect
@Component
public class MyAspect {@Before("execution(* com.example.service.*.*(..))")public void beforeAdvice() {System.out.println("Before advice: Performing actions before method execution.");}
}
在上述示例中,MyAspect
类被标识为一个切面,使用 @Before
注解定义了一个前置通知,该通知在执行 com.example.service
包下任何类的任何方法之前执行。
- 配置Spring启用AOP:
- 在 Spring 配置文件中,使用
<aop:aspectj-autoproxy>
元素启用 AspectJ 自动代理。
- 在 Spring 配置文件中,使用
<!-- applicationContext.xml -->
<beans xmlns="http://www.springframework.org/schema/beans"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xmlns:aop="http://www.springframework.org/schema/aop"xsi:schemaLocation="http://www.springframework.org/schema/beanshttp://www.springframework.org/schema/beans/spring-beans.xsdhttp://www.springframework.org/schema/aophttp://www.springframework.org/schema/aop/spring-aop.xsd"><aop:aspectj-autoproxy/><!-- 扫描包,使切面类成为 Spring 容器的 Bean --><context:component-scan base-package="com.example.aspect"/><!-- 其他配置 --></beans>
- 应用切面:
- 在需要应用切面的目标类上使用
@Component
或其他 Spring 注解,使其成为 Spring 容器的 Bean。
- 在需要应用切面的目标类上使用
package com.example.service;import org.springframework.stereotype.Service;@Service
public class MyService {public void doSomething() {System.out.println("Doing something...");}
}
在上述示例中,MyService
类上使用了 @Service
注解,使其成为 Spring 容器的 Bean。
通过上述步骤,当调用 MyService
类的 doSomething
方法时,切面中定义的前置通知将在方法执行之前被触发。
这是一个简单的 Spring AOP 的示例,实际应用中,你可以定义多个切面、不同类型的通知,以实现更复杂的横切关注点。 Spring AOP 提供了更多灵活的注解和表达式,可用于定义切入点和通知。
不同类型的通知,如前置通知、后置通知、环绕通知等。
在Spring AOP中,有几种常见的通知类型,用于定义横切关注点的不同执行时机。以下是不同类型的通知:
- 前置通知(Before Advice):
- 定义: 前置通知在目标方法执行之前执行。通常用于执行一些准备操作或校验。
- 示例:
@Aspect
@Component
public class MyAspect {@Before("execution(* com.example.service.*.*(..))")public void beforeAdvice() {System.out.println("Before advice: Performing actions before method execution.");}
}
- 后置通知(After Returning Advice):
- 定义: 后置通知在目标方法成功执行后执行。通常用于执行一些清理或日志记录等操作。
- 示例:
@Aspect
@Component
public class MyAspect {@AfterReturning("execution(* com.example.service.*.*(..))")public void afterReturningAdvice() {System.out.println("After returning advice: Performing actions after successful method execution.");}
}
- 异常通知(After Throwing Advice):
- 定义: 异常通知在目标方法抛出异常时执行。通常用于处理异常或记录异常信息。
- 示例:
@Aspect
@Component
public class MyAspect {@AfterThrowing(pointcut = "execution(* com.example.service.*.*(..))", throwing = "ex")public void afterThrowingAdvice(Exception ex) {System.out.println("After throwing advice: Handling exception - " + ex.getMessage());}
}
- 后置通知(After Advice):
- 定义: 后置通知在目标方法执行后无论成功与否都执行。通常用于执行一些清理操作。
- 示例:
@Aspect
@Component
public class MyAspect {@After("execution(* com.example.service.*.*(..))")public void afterAdvice() {System.out.println("After advice: Performing actions after method execution (regardless of success or failure).");}
}
- 环绕通知(Around Advice):
- 定义: 环绕通知包围目标方法的执行,提供对目标方法的完全控制。可以在目标方法执行前后进行任意操作。
- 示例:
@Aspect
@Component
public class MyAspect {@Around("execution(* com.example.service.*.*(..))")public Object aroundAdvice(ProceedingJoinPoint joinPoint) throws Throwable {System.out.println("Around advice: Before method execution.");// 执行目标方法Object result = joinPoint.proceed();System.out.println("Around advice: After method execution.");return result;}
}
上述示例中的 joinPoint.proceed()
负责手动调用目标方法的执行。环绕通知提供了最大的灵活性,但也需要谨慎使用,因为它要负责目标方法的执行。
在实际应用中,通常会根据具体需求选择合适的通知类型,并结合切入点表达式来定义切面。
5. Spring中的Bean:
Bean的概念和生命周期。
在Spring框架中,Bean是指由Spring容器管理的对象,它们构成了应用程序的主干。Bean的概念和生命周期是理解Spring框架的关键要素之一。
Bean的概念:
-
定义: Bean是由Spring IoC容器管理的对象。在Spring中,Bean是应用的基本构建块,可以是Java对象,也可以是其他由Spring框架管理的对象。
-
特点:
- Beans是由Spring容器实例化、装配和管理的。
- Beans由容器根据配置信息创建,它们通常代表应用程序中的一些重要的对象,例如服务、数据对象等。
- Beans之间可以有依赖关系,通过依赖注入,Spring容器可以将一个Bean注入到另一个Bean中。
-
创建方式: Beans可以通过XML配置、Java注解或Java代码的方式进行定义和配置。在Spring中,通常使用XML配置文件或使用注解来声明Beans。
Bean的生命周期:
Spring容器管理的每个Bean都具有生命周期,包括创建、初始化和销毁阶段。以下是Bean的生命周期阶段:
-
实例化(Instantiation):
- 当容器启动时,会实例化配置文件中定义的所有Bean。
- Spring通过构造函数或工厂方法来创建Bean的实例。
-
属性设置(Populate Properties):
- 容器通过setter方法或直接注入属性的方式来设置Bean的属性。
-
Bean的初始化(Initialization):
- 如果Bean实现了
InitializingBean
接口,或者在配置文件中通过init-method
指定了初始化方法,容器将调用这个方法。 - 这个阶段允许Bean执行一些初始化操作。
- 如果Bean实现了
-
Bean的使用:
- Bean已经被完全初始化,可以被应用程序使用。
-
Bean的销毁(Destruction):
- 如果Bean实现了
DisposableBean
接口,或者在配置文件中通过destroy-method
指定了销毁方法,容器将在销毁Bean之前调用这个方法。 - 这个阶段允许Bean执行一些清理操作。
- 如果Bean实现了
-
容器关闭:
- 当应用程序关闭时,Spring容器会关闭。在关闭过程中,容器会销毁所有的Bean,释放资源。
在配置文件中,可以使用以下方式指定初始化方法和销毁方法:
<bean id="myBean" class="com.example.MyBean" init-method="init" destroy-method="destroy"/>
对于注解配置,可以使用@PostConstruct
和@PreDestroy
注解来指定初始化和销毁方法:
import javax.annotation.PostConstruct;
import javax.annotation.PreDestroy;public class MyBean {@PostConstructpublic void init() {// 初始化操作}@PreDestroypublic void destroy() {// 销毁操作}
}
Bean的生命周期是Spring框架中重要的概念,了解Bean的创建、初始化和销毁过程有助于更好地设计和管理应用程序的组件。
如何使用@Component
、@Service
、@Repository
等注解声明Bean。
在Spring框架中,可以使用不同的注解来声明Bean。以下是常用的注解:
@Component
:@Component
是最通用的注解,用于将一个类声明为Spring容器中的Bean。- 示例:
import org.springframework.stereotype.Component;@Component
public class MyComponent {// 类的定义
}
@Service
:@Service
是@Component
的特化,用于声明服务层的Bean。- 示例:
import org.springframework.stereotype.Service;@Service
public class MyService {// 服务层Bean的定义
}
@Repository
:@Repository
是@Component
的特化,用于声明数据访问层(DAO)的Bean。- 示例:
import org.springframework.stereotype.Repository;@Repository
public class MyRepository {// 数据访问层Bean的定义
}
@Controller
:@Controller
是@Component
的特化,用于声明控制器层的Bean。- 示例:
import org.springframework.stereotype.Controller;@Controller
public class MyController {// 控制器层Bean的定义
}
这些注解都是@Component
的衍生,它们的作用是告诉Spring容器将被注解的类注册为一个Bean,并由容器进行管理。在使用这些注解声明Bean后,可以通过自动扫描或显式配置的方式将它们引入到Spring容器中。
自动扫描示例:
@Configuration
@ComponentScan(basePackages = "com.example")
public class AppConfig {// 配置类
}
上述配置类中的@ComponentScan
注解会自动扫描指定包下的所有带有@Component
及其派生注解的类,并将其注册为Spring容器中的Bean。
使用这些注解声明Bean可以简化配置,提高代码的可读性,并利用Spring的自动化装配特性。
作用域(Scope)的种类,如Singleton、Prototype等。
在Spring框架中,作用域(Scope)指定了Bean的生命周期范围,即Bean在容器中的存在时长。Spring定义了几种常见的作用域,其中最常用的是Singleton和Prototype。
- Singleton(默认):
- 定义: 默认作用域,表示一个Bean在整个应用中只有一个实例。
- 配置: 通过
@Scope("singleton")
注解或在XML配置中不设置scope
属性,都表示Singleton作用域。 - 示例:
@Component
@Scope("singleton")
public class MySingletonBean {// 类的定义
}
或者
<bean id="mySingletonBean" class="com.example.MySingletonBean"/>
- Prototype:
- 定义: 表示每次注入或通过容器获取Bean时都会创建一个新的实例。
- 配置: 通过
@Scope("prototype")
注解或在XML配置中设置scope
属性为"prototype"。 - 示例:
@Component
@Scope("prototype")
public class MyPrototypeBean {// 类的定义
}
或者
<bean id="myPrototypeBean" class="com.example.MyPrototypeBean" scope="prototype"/>
-
Request:
- 定义: 表示在一次HTTP请求中,一个Bean实例被共享。仅适用于Web应用。
- 配置: 通过
@Scope("request")
注解或在XML配置中设置scope
属性为"request"。
-
Session:
- 定义: 表示在一个HTTP Session中,一个Bean实例被共享。仅适用于Web应用。
- 配置: 通过
@Scope("session")
注解或在XML配置中设置scope
属性为"session"。
-
Application:
- 定义: 表示在整个Web应用中,一个Bean实例被共享。仅适用于Web应用。
- 配置: 通过
@Scope("application")
注解或在XML配置中设置scope
属性为"application"。
-
WebSocket:
- 定义: 表示在一个WebSocket会话中,一个Bean实例被共享。仅适用于Web应用。
- 配置: 通过
@Scope("websocket")
注解或在XML配置中设置scope
属性为"websocket"。
这些作用域允许开发者灵活地控制Bean的生命周期,根据应用的需求选择适当的作用域。默认情况下,Spring的作用域是Singleton。
Bean的生命周期回调方法,如init###method
和destroy###method
。
在Spring框架中,可以通过特定的生命周期回调方法来执行Bean的初始化和销毁操作。这些方法可以通过注解或XML配置来定义。
初始化方法:
- 使用
@PostConstruct
注解:- 通过
@PostConstruct
注解标记一个方法,该方法将在Bean的初始化阶段调用。 - 示例:
- 通过
import javax.annotation.PostConstruct;@Component
public class MyBean {@PostConstructpublic void init() {// 执行初始化操作System.out.println("Bean is being initialized...");}// 其他方法和定义
}
- 使用
init-method
属性(XML配置):- 在XML配置中,可以通过
init-method
属性指定一个初始化方法的名称。 - 示例:
- 在XML配置中,可以通过
<bean id="myBean" class="com.example.MyBean" init-method="init"/>
public class MyBean {public void init() {// 执行初始化操作System.out.println("Bean is being initialized...");}// 其他方法和定义
}
销毁方法:
- 使用
@PreDestroy
注解:- 通过
@PreDestroy
注解标记一个方法,该方法将在Bean销毁前调用。 - 示例:
- 通过
import javax.annotation.PreDestroy;@Component
public class MyBean {@PreDestroypublic void destroy() {// 执行销毁操作System.out.println("Bean is being destroyed...");}// 其他方法和定义
}
- 使用
destroy-method
属性(XML配置):- 在XML配置中,可以通过
destroy-method
属性指定一个销毁方法的名称。 - 示例:
- 在XML配置中,可以通过
<bean id="myBean" class="com.example.MyBean" destroy-method="destroy"/>
public class MyBean {public void destroy() {// 执行销毁操作System.out.println("Bean is being destroyed...");}// 其他方法和定义
}
注意:在Spring容器关闭时,会调用Bean的销毁方法。对于Singleton作用域的Bean,默认情况下,销毁方法会被调用。对于Prototype作用域的Bean,销毁方法需要由客户端代码显式调用。在使用@PreDestroy
注解或destroy-method
属性时,Spring容器将负责调用销毁方法。
6. 事务管理:
事务的概念和ACID特性。
事务(Transaction)是指一组相关的操作,它们被当作一个单一的工作单元来执行。事务是数据库管理系统(DBMS)中的一个重要概念,用于保持数据库的一致性和完整性。
ACID 特性:
ACID 是指事务应该具备的四个特性,确保数据库在事务的执行过程中保持可靠性和稳定性。
-
原子性(Atomicity):
- 事务的原子性要求事务中的所有操作,要么全部执行成功,要么全部执行失败,没有中间状态。如果事务中的任何一部分操作失败,整个事务将被回滚到事务开始前的状态。
-
一致性(Consistency):
- 事务的一致性要求事务在执行前后,数据库从一个一致的状态转移到另一个一致的状态。在事务执行过程中,数据库必须满足一定的约束条件,以保持数据的完整性。
-
隔离性(Isolation):
- 隔离性描述了多个事务并发执行时,每个事务都应该被隔离,不应该受到其他事务的影响。每个事务应该感觉到它是唯一在数据库中执行的事务。
-
持久性(Durability):
- 持久性要求一旦事务成功提交,对数据库的修改就是永久性的,即使系统发生故障,数据库也应该能够在恢复后保持这些修改。
这四个特性确保了事务的可靠性和数据库的稳定性。数据库管理系统通过事务的提交和回滚来实现这些特性。
事务的概念:
-
事务的开始和结束:
- 事务通常以
BEGIN TRANSACTION
开始,以COMMIT
或ROLLBACK
结束。COMMIT
表示事务成功,ROLLBACK
表示事务失败并进行回滚。
- 事务通常以
-
事务的隔离级别:
- 隔离级别定义了在多个事务同时执行时,一个事务对其他事务的影响程度。常见的隔离级别包括:读未提交(Read Uncommitted)、读已提交(Read Committed)、可重复读(Repeatable Read)和串行化(Serializable)。
-
事务管理:
- 事务管理包括事务的提交和回滚。当事务成功完成时,通过
COMMIT
来提交事务。如果发生错误或违反了事务的某些条件,通过ROLLBACK
来回滚事务。
- 事务管理包括事务的提交和回滚。当事务成功完成时,通过
-
嵌套事务:
- 有些数据库支持嵌套事务,允许在一个事务内启动另一个事务。嵌套事务的提交和回滚不会立即影响外部事务,而是在外部事务提交时生效。
事务是数据库管理系统中确保数据完整性和一致性的重要机制,它允许将一系列相关的操作看作一个不可分割的单元。 ACID 特性确保了事务的可靠性和数据库的稳定性。
在Spring中如何声明式和编程式管理事务。
在Spring中,事务管理可以通过声明式事务管理和编程式事务管理来实现。
1. 声明式事务管理:
声明式事务管理是通过配置的方式实现的,通常使用Spring的AOP(面向切面编程)来处理事务。主要通过注解或XML配置来声明事务。
使用注解方式:
使用@Transactional
注解来声明事务,可以放在类级别或方法级别。
import org.springframework.transaction.annotation.Transactional;@Service
public class MyService {@Transactionalpublic void myTransactionalMethod() {// 事务中的业务逻辑}
}
使用XML配置方式:
在Spring的XML配置文件中配置事务管理器和切面,声明事务的属性。
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager"><property name="dataSource" ref="dataSource"/>
</bean><tx:advice id="txAdvice" transaction-manager="transactionManager"><tx:attributes><tx:method name="myTransactionalMethod" propagation="REQUIRED"/></tx:attributes>
</tx:advice><aop:config><aop:pointcut id="txPointcut" expression="execution(* com.example.MyService.myTransactionalMethod(..))"/><aop:advisor advice-ref="txAdvice" pointcut-ref="txPointcut"/>
</aop:config>
2. 编程式事务管理:
编程式事务管理是通过编写代码来实现事务管理。在需要事务的地方,通过编程方式调用事务管理相关的方法。
使用TransactionTemplate
:
import org.springframework.transaction.support.TransactionTemplate;@Service
public class MyService {private final TransactionTemplate transactionTemplate;@Autowiredpublic MyService(PlatformTransactionManager transactionManager) {this.transactionTemplate = new TransactionTemplate(transactionManager);}public void myTransactionalMethod() {transactionTemplate.execute(status -> {try {// 事务中的业务逻辑return true;} catch (Exception e) {status.setRollbackOnly();return false;}});}
}
使用TransactionInterceptor
:
import org.springframework.transaction.interceptor.TransactionInterceptor;@Service
public class MyService {@Autowiredprivate TransactionInterceptor transactionInterceptor;public void myTransactionalMethod() {transactionInterceptor.invoke(new MethodInvocation() {@Overridepublic Object proceed() throws Throwable {// 事务中的业务逻辑return null;}// 其他方法的实现});}
}
在实际项目中,通常使用声明式事务管理更为方便,因为它能够通过注解或XML配置集中管理事务,并且使代码更加清晰和简洁。
@Transactional
注解的使用。
@Transactional
注解是Spring框架提供的声明式事务管理的关键注解之一,用于在方法或类上标记事务行为。该注解可用于类级别和方法级别。
在方法上使用@Transactional
:
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;@Service
public class MyService {@Transactionalpublic void myTransactionalMethod() {// 事务中的业务逻辑}
}
@Transactional
注解的常用属性:
- propagation(传播行为):
- 指定事务的传播行为,定义了当前事务方法与另一个事务方法交互的方式。常用选项包括
REQUIRED
、REQUIRES_NEW
等。
- 指定事务的传播行为,定义了当前事务方法与另一个事务方法交互的方式。常用选项包括
@Transactional(propagation = Propagation.REQUIRED)
public void myTransactionalMethod() {// 事务中的业务逻辑
}
- isolation(隔离级别):
- 指定事务的隔离级别,定义了一个事务对数据的锁定程度。常用选项包括
DEFAULT
、READ_COMMITTED
、SERIALIZABLE
等。
- 指定事务的隔离级别,定义了一个事务对数据的锁定程度。常用选项包括
@Transactional(isolation = Isolation.READ_COMMITTED)
public void myTransactionalMethod() {// 事务中的业务逻辑
}
- readOnly(只读事务):
- 指定事务是否为只读事务,如果是只读事务,就不会对数据进行修改操作。
@Transactional(readOnly = true)
public void myTransactionalMethod() {// 只读事务中的业务逻辑
}
- timeout(超时时间):
- 指定事务的超时时间,单位为秒。
@Transactional(timeout = 30)
public void myTransactionalMethod() {// 事务中的业务逻辑
}
- rollbackFor 和 noRollbackFor:
rollbackFor
指定哪些异常会触发事务回滚,noRollbackFor
指定哪些异常不会触发事务回滚。
@Transactional(rollbackFor = MyException.class, noRollbackFor = AnotherException.class)
public void myTransactionalMethod() throws MyException, AnotherException {// 事务中的业务逻辑
}
- value 和 transactionManager:
value
用于指定事务管理器的bean名称,如果有多个事务管理器时使用。transactionManager
也可以直接指定事务管理器的bean名称。
@Transactional(value = "myTransactionManager")
public void myTransactionalMethod() {// 事务中的业务逻辑
}
在类上使用@Transactional
:
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;@Service
@Transactional
public class MyService {public void myTransactionalMethod() {// 事务中的业务逻辑}
}
在类级别上使用@Transactional
注解会使类中的所有方法都具有相同的事务属性。方法级别的@Transactional
注解会覆盖类级别的注解。
@Service
@Transactional
public class MyService {public void method1() {// 事务中的业务逻辑}@Transactional(propagation = Propagation.REQUIRES_NEW)public void method2() {// 使用新的事务}
}
以上是@Transactional
注解的基本用法和常用属性。通过这个注解,可以轻松地实现声明式事务管理,而不需要显式地编写事务管理代码。
事务传播行为和隔离级别的了解。
在Spring事务管理中,事务传播行为(Propagation)和隔离级别(Isolation)是两个重要的概念,用于定义事务方法在嵌套调用或并发执行时的行为。
1. 事务传播行为(Propagation):
事务传播行为定义了一个事务方法与另一个事务方法交互的方式。在Spring中,可以使用@Transactional
注解的propagation
属性来指定事务传播行为。
常见的事务传播行为包括:
- REQUIRED(默认):
- 如果当前存在事务,则加入该事务;如果当前没有事务,则创建一个新的事务。
@Transactional(propagation = Propagation.REQUIRED)
public void method1() {// 事务中的业务逻辑
}@Transactional(propagation = Propagation.REQUIRED)
public void method2() {// method1() 和 method2() 将共享同一个事务
}
- REQUIRES_NEW:
- 创建一个新的事务,并挂起当前事务(如果存在)。
@Transactional(propagation = Propagation.REQUIRES_NEW)
public void method1() {// 事务中的业务逻辑
}@Transactional(propagation = Propagation.REQUIRES_NEW)
public void method2() {// method1() 和 method2() 将使用各自独立的事务
}
- SUPPORTS:
- 如果当前存在事务,则加入该事务;如果当前没有事务,则以非事务方式执行。
@Transactional(propagation = Propagation.SUPPORTS)
public void method1() {// 可能在事务中执行,也可能不在事务中执行
}@Transactional(propagation = Propagation.SUPPORTS)
public void method2() {// method1() 和 method2() 将根据调用上下文来决定是否在事务中执行
}
- NOT_SUPPORTED:
- 以非事务方式执行,并挂起当前事务(如果存在)。
@Transactional(propagation = Propagation.NOT_SUPPORTED)
public void method1() {// 以非事务方式执行
}@Transactional(propagation = Propagation.NOT_SUPPORTED)
public void method2() {// method1() 和 method2() 将以非事务方式执行
}
- NEVER:
- 以非事务方式执行,如果当前存在事务,则抛出异常。
@Transactional(propagation = Propagation.NEVER)
public void method1() {// 以非事务方式执行
}@Transactional(propagation = Propagation.NEVER)
public void method2() {// 如果有事务存在,则抛出异常
}
- MANDATORY:
- 如果当前存在事务,则加入该事务;如果当前没有事务,则抛出异常。
@Transactional(propagation = Propagation.MANDATORY)
public void method1() {// 必须在事务中执行
}@Transactional(propagation = Propagation.MANDATORY)
public void method2() {// method1() 和 method2() 都必须在事务中执行
}
- NESTED:
- 如果当前存在事务,则创建一个嵌套事务,并在嵌套事务内执行;如果当前没有事务,则创建一个新的事务。
@Transactional(propagation = Propagation.NESTED)
public void method1() {// 创建一个嵌套事务
}@Transactional(propagation = Propagation.NESTED)
public void method2() {// method1() 和 method2() 将共享同一个嵌套事务
}
2. 隔离级别(Isolation):
隔离级别定义了一个事务对数据的锁定程度,以及一个事务对另一个事务的影响程度。在Spring中,可以使用@Transactional
注解的isolation
属性来指定事务的隔离级别。
常见的隔离级别包括:
-
DEFAULT:
- 使用默认的数据库隔离级别,通常为数据库的默认隔离级别。
-
READ_UNCOMMITTED:
- 允许事务读取未提交的数据,是隔离级别最低的。
-
READ_COMMITTED:
- 确保一个事务不能读取另一个事务未提交的数据,是大多数数据库的默认隔离级别。
关注公众号 洪都新府笑颜社,发送 “面试题” 即可免费领取一份超全的面试题PDF文件!!!!