事务
什么是事务?
事务是一组操作的集合,它是一个不可分割的工作单位。事务会把所有的操作作为一个整体,一起向数据库提交或者是撤销操作请求。所以这组操作要么同时成功,要么同时失败。
事务的操作主要有三步:
- 开启事务(一组操作开始前,开启事务):start transaction / begin ;
- 提交事务(这组操作全部成功后,提交事务):commit ;
- 回滚事务(中间任何一个操作出现异常,回滚事务):rollback ;
事务管理
现在只需通过 @Transactional注解就可以对事务管理
其中的属性:
- 异常回滚的属性:rollbackFor
结论:
- 在Spring的事务管理中,默认只有运行时异常 RuntimeException才会回滚。
- 如果还需要回滚指定类型的异常,可以通过rollbackFor属性来指定。
-
事务传播行为:propagation
propagation,这个属性是用来配置事务的传播行为的。
什么是事务的传播行为呢?
- 就是当一个事务方法被另一个事务方法调用时,这个事务方法应该如何进行事务控制
对于这些事务传播行为,重点只需要关注以下两个就可以了:
- REQUIRED(默认值)
- 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的核心概念
AOP的优势:
- 减少重复代码
- 提高开发效率
- 维护方便
通知类型
切点表达式
execution主要根据方法的返回值、包名、类名、方法名、方法参数等信息来匹配,语法为:
execution(访问修饰符? 返回值 包名.类名.?方法名(方法参数) throws 异常?)
其中带?的表示可以省略的部分
- 访问修饰符:可省略(比如: public、protected)
- 包名.类名: 可省略
- throws 异常:可省略(注意是方法上声明抛出的异常,不是实际抛出的异常)
示例:
@Before("execution(void com.itheima.service.impl.DeptServiceImpl.delete(java.lang.Integer))")
可以使用通配符描述切入点
*:单个独立的任意符号,可以通配任意返回值、包名、类名、方法名、任意类型的一个参数,也可以通配包、类、方法名的一部分..:多个连续的任意符号,可以通配任意层级的包,或任意类型、任意个数的参数
切入点表达式的语法规则:
- 方法的访问修饰符可以省略
- 返回值可以使用
*号代替(任意返回值类型) - 包名可以使用
*号代替,代表任意包(一层包使用一个*) - 使用
..配置包名,标识此包以及此包下的所有子包 - 类名可以使用
*号代替,标识任意类 - 方法名可以使用
*号代替,表示任意方法 - 可以使用
*配置参数,一个任意类型的参数 - 可以使用
..配置参数,任意个任意类型的参数
先使用元注解定义
@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;
}
}