SpringBoot 事务管理与AOP

本文探讨了SpringBoot中的事务管理和AOP概念。事务管理通过@Transactional注解在Service层进行,异常处理可自定义。介绍了事务的传播方式,AOP的作用及其实现,包括连接点、通知、切入点和切面的定义,以及通知的类型和执行顺序。同时讲解了如何创建AOP入门案例,以及切点表达式的定义和管理。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

事务是什么?在MySQL中是怎么去开启,提交,回滚事务的。

  1. 事务是一组操作的集合,这些操作要么全部成功,要么全部失败;
  2. 在MySql中事务是默认提交的(每一条SQL语句开启一个事务);
  3. 在MySql中手动开启、提交、回滚事务:
        手动开启事务(一组操作开始前,开启事务):start transaction 或 begin ;
        提交事务(这组操作全部成功后,提交事务):commit ;
        回滚事务(中间任何一个操作出现异常,回滚事务):rollback ;

在Spring中怎么管理事务,用什么注解,在那个层次进行使用可以有效管理事务

  1. 在Spring中可以使用@Transactional注解来管理事务;
  2. 在service层添加事务注解(因为事务所控制的是一组操作的集合,而只有在业务层才会存在一个业务功能包含多个数据访问操作)

事务管理时规则:如果方法能够正常执行完自动提交事务,如果出现异常自动回滚事物。事务默认识别的异常是运行时异常,如果想要识别到编译时异常从而实现回滚,该怎么操作?

  1. @Transactional注解上添加rollbackFor这个属性可以指定出现何种异常类型回滚事务
@Transactional(rollbackFor=Exception.class)

事务的传播方式有哪些,含义是怎样?

AOP叫做什么,有什么作用?举一个5岁孩子就能理解的例子?

  1. AOP英文全称:Aspect Oriented Programming(面向切面编程、面向方面编程)面向切面编程其实就是面向特定方法编程;
  2. AOP的作用:在程序运行期间在不修改源代码的基础上对已有方法进行增强(无侵入性: 解耦)

小明玩游戏时,我们可以在每次他攻击怪兽之前和之后记录攻击次数。这样,我们可以知道他一共攻击了多少次怪兽。这就是AOP的作用,它可以在不改变原有游戏逻辑的情况下,添加额外的功能

如果要完成一个AOP的入门案例,需要有哪些步骤?

        1、导入AOP起步依赖

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-aop</artifactId>
</dependency>

        2、定义切面类类中编写公共代码(统计执行耗时操作)

        3、标识当前类是一个AOP类,并被Spring容器管理

        4、配置公共代码作用于哪些目标方法

        5、执行目标方法

@Component //该注解表示当前类被Spring容器管理
@Aspect //该注解表示当前类为切面类
@Slf4j //日志依赖
public class TimeAspect {

    @Around("execution(* com.itheima.service.*.*(..))")
    public Object recordTime(ProceedingJoinPoint pjp) throws Throwable {
        //记录方法执行开始时间
        long begin = System.currentTimeMillis();

        //执行原始方法
        Object result = pjp.proceed();

        //记录方法执行结束时间
        long end = System.currentTimeMillis();

        //计算方法执行耗时
        log.info(pjp.getSignature()+"执行耗时: {}毫秒",end-begin);

        return result; //返回原始方法执行结果
    }
}

AOP的概念理解:连接点,通知,切入点,切面 ?

        连接点:JoinPoint,可以被AOP控制的方法(需要被增强功能的原始方法

        通知:Advice,指那些重复的逻辑,也就是共性功能(对原始方法功能进行增强的代码

        切入点:PointCut,匹配连接点的条件,通知仅会在切入点方法执行时被应用(筛选需要被增强的方法

        切面:Aspect,描述通知与切入点的对应关系(通知+切入点

通知有哪些类型?

@Around:环绕通知,此注解标注的通知方法在目标方法前、后都被执行;
@Before:前置通知,此注解标注的通知方法在目标方法前被执行;
@After :后置通知,此注解标注的通知方法在目标方法后被执行,无论是否有异常都会执行;
@AfterReturning : 返回后通知,此注解标注的通知方法在目标方法后被执行,有异常不会执行;
@AfterThrowing : 异常后通知,此注解标注的通知方法发生异常后执行;

如果有不同切面的通知,增强相同的方法,执行顺序是怎样的?

默认按照切面类的类名字母排序:

        目标方法前的通知方法:字母排名靠前的先执行

        目标方法后的通知方法:字母排名靠前的后执行

如果我们想控制通知的执行顺序有两种方式:

1. 修改切面类的类名(这种方式非常繁琐、而且不便管理)
2. 使用Spring提供的@Order注解

        使用@Order注解:注解中属性值小的先执行
        使用@Order注解:注解中属性值大的后执行

切点表达式有几种,具体怎么定义?

1、execution(……):根据方法的签名来匹配

execution主要根据方法的返回值、包名、类名、方法名、方法参数等信息来匹配,语法为:

execution(访问修饰符?  返回值  包名.类名.?方法名(方法参数) throws 异常?)

其中带`?`的表示可以省略的部分

        访问修饰符:可省略(比如: public、protected)

        包名.类名: 可省略

        throws 异常:可省略(注意是方法上声明抛出的异常,不是实际抛出的异常)

示例:

@Before("execution(void com.itheima.service.impl.DeptServiceImpl.delete(java.lang.Integer))")

可以使用通配符描述切入点

        `*` :单个独立的任意符号,可以通配任意返回值、包名、类名、方法名、任意类型的一个参数,也可以通配包、类、方法名的一部分

        `..` :多个连续的任意符号,可以通配任意层级的包,或任意类型、任意个数的参数

切入点表达式的语法规则:

  1. 方法的修饰符可以省略
  2. 返回值可以使用`*`号代替(任意返回值类型)
  3. 包名可以使用`*`号代替,代表任意包(一层包使用一个`*`)
  4. 使用`..`配置包名,标识此包以及此包下的所有子包
  5. 类名可以使用`*`号代替,标识任意类
  6. 方法名可以使用`*`号代替,表示任意方法
  7. 可以使用`..`配置参数,任意参数

注意事项:

        根据业务需要,可以使用 且(&&)、或(||)、非(!) 来组合比较复杂的切入点表达式。

2、@annotation(……) :根据注解匹配

实现步骤:

  1. 编写自定义注解

  2. 在业务类要做为连接点的方法上添加自定义注解

自定义注解:MyLog

@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface MyLog {
}

如果有多个通知的切点表达式一样,怎么抽取?

使用@PointCut注解进行抽取:

连接点是什么可以获取哪些信息?

连接点可以简单理解为可以被AOP控制的方法,在SpringAOP当中,连接点又特指方法的执行;

在Spring中用JoinPoint抽象了连接点,用它可以获得方法执行时的相关信息,如目标类名、方法名、方法参数等。

        对于@Around通知,获取连接点信息只能使用ProceedingJoinPoint类型

        对于其他四种通知,获取连接点信息只能使用JoinPoint,它是ProceedingJoinPoint的父类型

//环绕通知
    @Around("pt()")
    public Object around(ProceedingJoinPoint pjp) throws Throwable {
        //获取执行的目标方法全类类名
        String name = pjp.getTarget().getClass().getName();
        log.info("目标类名:{}",name);

        //目标方法名
        String methodName = pjp.getSignature().getName();
        log.info("目标方法名:{}",methodName);

        //获取方法执行时需要的参数(实参)
        Object[] args = pjp.getArgs();
        log.info("目标方法参数:{}", Arrays.toString(args));

    

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值