事务回滚技术及AOP操作技术

128 阅读4分钟

事务

什么是事务?

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

事务的操作主要有三步:

  1. 开启事务(一组操作开始前,开启事务):start transaction / begin ;
  2. 提交事务(这组操作全部成功后,提交事务):commit ;
  3. 回滚事务(中间任何一个操作出现异常,回滚事务):rollback ;

事务管理

现在只需通过 @Transactional注解就可以对事务管理

其中的属性:

  1. 异常回滚的属性rollbackFor

结论:

  • 在Spring的事务管理中,默认只有运行时异常 RuntimeException才会回滚。
  • 如果还需要回滚指定类型的异常,可以通过rollbackFor属性来指定。
  1. 事务传播行为propagation

    propagation,这个属性是用来配置事务的传播行为的。

什么是事务的传播行为呢?

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

image.png 对于这些事务传播行为,重点只需要关注以下两个就可以了:

  1. REQUIRED(默认值)
  2. REQUIRES_NEW
@Service
public class DeptLogServiceImpl implements DeptLogService {

    @Autowired
    private DeptLogMapper deptLogMapper;

    @Transactional(propagation = Propagation.REQUIRES_NEW) //事务传播行为:有事务就加入、没有事务就新建事务
    @Override
    public void insert(DeptLog deptLog) {
        deptLogMapper.insert(deptLog);
    }
}

AOP

什么是AOP?

  • AOP英文全称:Aspect Oriented Programming(面向切面编程、面向方面编程),其实说白了,面向切面编程就是面向特定方法编程

AOP面向方法编程,就可以做到在不改动这些原始方法的基础上,针对特定的方法进行功能的增强。 AOP( 面向切面编程 )是一种思想,它的目的就是在不修改源代码的基础上,对原有功能进行增强。

SpringAOP是对AOP思想的一种实现,Spring底层同时支持jdk和cglib动态代理。

Spring会根据被代理的类是否有接口自动选择代理方式:

  • 如果有接口,就采用jdk动态代理
  • 如果没接口,就采用cglib的方式

AOP的核心概念

image.png

AOP的优势:

  1. 减少重复代码
  2. 提高开发效率
  3. 维护方便
通知类型

image.png

image.png

切点表达式

image.png 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. 可以使用 * 配置参数,一个任意类型的参数
  8. 可以使用.. 配置参数,任意个任意类型的参数

image.png

先使用元注解定义

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

AOP的使用:

1.先导入依赖
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-aop</artifactId>
</dependency>
2.定义AOP程序:TimeAspect

import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.*;
import org.springframework.stereotype.Component;

@Component
@Aspect //当前类为切面类
@Slf4j
public class TimeAspect {
    **execution方式**
    @Pointcut("execution(* com.org.service.*.*(..))")//切入点表达式 
    private void pt(){}
    
     **annotation方式**
    @Pointcut("@annotation(com.itheima.anno.MyLog)")
    private void pt(){}
  
**  两种方式任选其一**
  
    //前置通知
    @Before("pt()")
    public void before(JoinPoint joinPoint){
        System.out.println("即将进入方法");
    }

    //后置通知
    @After("pt()")
    public void after(JoinPoint joinPoint){
        System.out.println("方法运行到最后");
    }
    //返回后通知
@AfterReturning("pt()")
public void returnMethod(){
    System.out.println("方法正常结束");
}
//异常后通知
@AfterThrowing("pt()")
public void Throw(){
    System.out.println("方法出现异常");
}
    @Around("pt()")
    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;
    }
}