SpringBoot事务管理+AOP

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

事务 是一组操作的集合,它是一个不可分割的工作单位,事务会把所有的操作作为一个整体一起向系统提交或撤销操作请求,即这些操作 要么同时成功,要么同时失败

在MySQL中:

开启事务(一组操作开始前,开启事务)start   transaction / begin ;

提交事务(这组操作全部成功后,提交事务)commit ;

回滚事务(中间任何一个操作出现异常,回滚事务)rollback ;

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

注解:@Transactional

位置:业务(service)层的方法上、类上、接口上

开启管理日志:

logging:
    level:    
      org.springframework.jdbc.support.JdbcTransactionManager: debug

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

事务管理注解@Transactional中的rollbackFor属性默认情况下,只有出现RuntimeException才回滚异常。而如果出现编译时异常,则不回滚

如果想要实现编译时异常回滚,有两种方法

  • 第一种方法是直接甩锅抛出异常,设置rollbackFor属性值为Exception.class,支持多态
 //    删除部门
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void deleteDept(Integer id) throws FileNotFoundException{
//      删除部门
        deptMapper.deleteById(id);


//        模拟编译时异常
        new FileInputStream("***/***/***.txt");

//        删除该部门对应的员工
        empMapper.deleteByDeptId(id);
    }
  • 第二种方法是使用try,catch语句捕获编译异常,在catch中抛出(throw)运行异常完成转换,从而实现回滚
//    删除部门
    @Override
    @Transactional //Spring事务管理
    public void deleteDept(Integer id){
//      删除部门
        deptMapper.deleteById(id);


//        模拟编译时异常
        try {
            new FileInputStream("***/***/***.txt");
        } catch (FileNotFoundException e) {
            throw new RuntimeException(e.getMessage());//抛出运行时异常
        }

//        删除该部门对应的员工
        empMapper.deleteByDeptId(id);
    }

推荐使用第二种方式,因为第一种如果是实现类,其实现的接口没有处理异常,则父类也要抛出异常,较为麻烦

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

事务传播

指的就是当一个事务方法被另一个事务方法调用时,这个事务方法应该如何进行事务控制。

属性值

含义

说明

REQUIRE

【默认值】需要事务,有则加入,无则创建新事务

-

REQUIRES_NEW

需要新事务,无论有无,总是创建新事务

-

SUPPORTS

支持事务,有则加入,无则在独立的连接中运行 SQL

结合 Hibernate、JPA  时有用,配在查询方法上

NOT_SUPPORTED

不支持事务,不加入,在独立的连接中运行 SQL

-

MANDATORY

必须有事务,否则抛异常

-

NEVER

必须没事务,否则抛异常

-

NESTED

嵌套事务

仅对 DataSourceTransactionManager  有效

 对于这么多事务传播方式,前两个最为常用

5.AOP叫做什么,有什么作用?举个例子?

AOP:Aspect Oriented Programming(面向切面编程),

作用:将重复的逻辑剥离出来,在不修改原始逻辑的基础上对原始功能进行增强。

举例

        小明每天都要去学校上课。但是,他经常会忘记带自己的书包。为了帮助小明记得带书包,他的妈妈在家门口贴了一张便签纸,上面写着:“记得带书包哦!”每天早上,小明在出门前都会看到这张便签纸,提醒他带书包。

        这里,无论小明做什么,只要他看到便签纸,就会自动记得带书包。就像小明的妈妈使用便签纸帮助他记得带书包一样,AOP可以帮助我们将一些重复的行为(比如日常提醒、规则检查等)从主要的任务中分离出来,提供更好的组织和管理方式。

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

(1) pom.xml 引入依赖

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

 (2) 定义类抽取公共代码

@Component //声明该类是spring的IOC容器中的bean对象
@Aspect //标识当前类是一个AOP类
@Slf4j //日志
public class TimeAspect {
	
    public void recordTime() throws Throwable {
        long begin = System.currentTimeMillis();
        
        //调用原始操作
        
        
        long end = System.currentTimeMillis();
        log.info("执行耗时 : {} ms", (end-begin));
    }
	
}

 (3) 配置公共代码作用于哪些目标方法

@Component
@Aspect
@Slf4j
public class TimeAspect {
	//注解@Around:表示环绕通知,可以在目标方法执行前后执行一些公共代码
    //* 表示通配符,代表任意
    //.. 表示参数通配符,代表任意参数
    @Around("execution(* com.itheima.service.impl.DeptServiceImpl.*(..))")
    public void recordTime() throws Throwable {
        long begin = System.currentTimeMillis();
        
        //调用原始操作
        
        
        long end = System.currentTimeMillis();
        log.info("执行耗时 : {} ms", (end-begin));
    }
	
}

 (4) 执行目标方法

@Component
@Aspect
@Slf4j
public class TimeAspect {
	
    @Around("execution(* com.itheima.service.impl.DeptServiceImpl.*(..))")
    public Object recordTime(ProceedingJoinPoint joinPoint) throws Throwable {
        long begin = System.currentTimeMillis();
        //调用原始操作
        Object result = joinPoint.proceed();
        long end = System.currentTimeMillis();
        log.info("执行耗时 : {} ms", (end-begin));
        return result;
    }
    
}

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

  • 连接点:JoinPoint,可以被AOP控制的方法执行(包含方法信息)
  • 通知:Advice ,重复逻辑代码
  • 切入点:PointCut ,匹配连接点的条件
  • 切面:Aspect,通知+切点

8.通知有哪些类型?

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

注:@Around需要自己调用 ProceedingJoinPoint.proceed() 来让目标方法执行,其他通知不需要考虑目标方法执行

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

当有多个切面的切点都匹配目标时,多个通知方法都会被执行。

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

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

@Order(数字) 加在切面类上来控制顺序

  • 目标前的通知方法:数字小先执行
  • 目标后的通知方法:数字小后执行

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

常见的切点表达式

execution(返回值类型 包名.类名.方法名(参数类型))

@annotation() 根据注解匹配

(1)execution

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

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

 其中带 [ ] 的参数信息可省略不写

(2)annotation

切点表达式也支持匹配目标方法是否有注解。使用 @annotation

@annotation(com.itheima.anno.Log)

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

通过@PointCut注解,可以抽取一个切点表达式,然后再其他的地方我们就可以通过类似于  方法调用 的形式来引用该切点表达式。

    @Pointcut("execution(* com.itheima.service.impl.DeptServiceImpl.*(..))")
    public void pt(){}

    @Around("pt()")
    public Object recordTime(ProceedingJoinPoint joinPoint) throws Throwable {
        long begin = System.currentTimeMillis();
        //调用原始操作
        Object result = joinPoint.proceed();
        long end = System.currentTimeMillis();
        log.info("执行耗时 : {} ms", (end-begin));
        return result;
    }

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

连接点简单理解就是目标方法,在Spring 中用 JoinPoint 抽象了连接点,用它可以获得方法执行时的相关信息,如方法名、方法参数类型、方法实际参数等等

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

代码如下:

@Slf4j
@Aspect
@Component
public class MyAspect1 {

    @Pointcut("execution(* com.itheima.service.impl.*.*(..)) && @annotation(com.itheima.anno.Log)")
    public void pt(){}

    @Before("pt()")
    public void before(JoinPoint joinPoint){

        log.info("方法名: "+joinPoint.getSignature().getName());
        log.info("类名: "+joinPoint.getTarget().getClass().getName());
        log.info("参数: "+Arrays.asList(joinPoint.getArgs()).toString());

        log.info("before...1");
    }
}

  • 7
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 2
    评论
Spring Boot 是一个用于快速构建 Java 应用程序的框架。它可以与多种其他框架和组件进行整合,以实现更丰富的功能。在这里,我们将讨论如何使用 Spring Boot 整合 Druid、MyBatis、JTA 分布式事务以及多数据源,同时使用 AOP 注解实现动态切换。 首先,我们可以在 Spring Boot 中集成 Druid 数据源。Druid 是一个高性能的 JDBC 连接池,可以提供监控和统计功能。我们可以通过在 pom.xml 文件中添加相关的依赖,并在 application.properties 文件中配置数据源信息,来实现 Druid 的集成。 接下来,我们可以整合 MyBatis 框架,它是一种优秀的持久化解决方案。我们可以使用 MyBatis 来操作数据库,并将其与 Druid 数据源进行整合。为此,我们需要在 pom.xml 文件中添加 MyBatis 和 MyBatis-Spring 的依赖,并配置 MyBatis 的相关配置文件。 此外,我们还可以使用 JTA(Java Transaction API)实现分布式事务。JTA 可以在分布式环境中协调多个参与者的事务操作。我们可以在 pom.xml 文件中添加 JTA 的依赖,并在 Spring Boot 的配置文件中配置 JTA 的相关属性,以实现分布式事务的支持。 在实现多数据源时,我们可以使用 Spring Boot 的 AbstractRoutingDataSource 来实现动态切换数据源。这个类可以根据当前线程或其他条件选择不同的数据源来进行数据操作。我们可以通过继承 AbstractRoutingDataSource 并实现 determineCurrentLookupKey() 方法来指定当前数据源的 key。然后,在配置文件中配置多个数据源,并将数据源注入到 AbstractRoutingDataSource 中,从而实现动态切换。 最后,我们可以使用 AOP(Aspect Oriented Programming)注解来实现动态切换。AOP 是一种编程范式,可以通过在代码中插入特定的切面(Aspect)来实现横切关注点的处理。我们可以在代码中使用注解来标记需要切换数据源的方法,然后使用 AOP 技术来拦截这些方法,并根据注解中指定的数据源信息来进行数据源的切换。 综上所述,通过整合 Druid、MyBatis、JTA 分布式事务以及多数据源,并使用 AOP 注解实现动态切换,我们可以在 Spring Boot 中实现强大而灵活的应用程序。
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

笑看夕阳染红天

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值