web后端事务管理AOP

事务管理

事务回顾

事务        是一组操作的集合,他是一个不可分割的工作单位,这些操作        要么同时成功,要么同时失败。

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

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

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

spring事务管理

注解@Transactional

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

作用:将当前方法交给spring进行事务管理,方法执行前,开启事务。成功执行完毕,提交事务。出现异常,回滚事务

在application中开启事务日志

//empmapper
//    根据部门id删除该部门下的员工数据
    @Delete("delete from emp where dept_id=#{deptId}")
    void deleteByDeptID(Integer deptId);
//deptservice实现类
 @Autowired
    private EmpMapper empMapper;//注入(在mapper接口中)
@Transactional//spring事务管理
@Override
    public void delete(Integer id) {
        deptMapper.deleteById(id);//删除部门
        empMapper.deleteByDeptID(id);//根据id删除部门下员工
    }
//application中开启事务日志
#开启事务管理
logging:
  level:
    org.springframework.jdbc.support.JdbcTransactionManager:debug

事务进阶

rollbackFor

默认情况下,只有出现RuntimeException才会回滚异常。rollbackFor属性用于控制出现何种异常类型,回滚事务        

@Transactional(rollbackFor = Exception.class)
//service层
@Transactional(rollbackFor = Exception.class)//spring事务管理
    @Override
    public void delete(Integer id) throws Exception {
        deptMapper.deleteById(id);//删除部门
        if (true){
            throw new Exception("出错啦");  //抛异常
        }
        empMapper.deleteByDeptID(id);//根据id删除部门下员工
    }
//controller层
  /*删除部门*/
    @DeleteMapping("/{id}")
    public Result delete(@PathVariable Integer id) throws Exception {   //抛异常
        log.info("根据id删除部门,{}",id);
        //调用service删除部门
        deptService.delete(id);
        return Result.success();
    }

propagation

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

//database
create table dept_log
(
    id          int auto_increment
        primary key,
    create_time datetime    null comment '创建时间',
    description varchar(20) null comment '描述信息
'
);
//deptservice实体类  ctrl+alt+t快速创建try  final方法
 @Transactional
    @Override
    public void delete(Integer id) throws Exception {
        try {
            deptMapper.deleteById(id);//删除部门
            int i=1/0;
//        if (true){
//            throw new Exception("出错啦");  //抛异常
//        }
            empMapper.deleteByDeptID(id);//根据id删除部门下员工
        } finally {
            DeptLog deptLog = new DeptLog();
            deptLog.setCreateTime(LocalDateTime.now());
            deptLog.setDescription("执行了解散部门的操作,此次解散的是"+id+"号部门");
            deptLogService.insert(deptLog);
        }
    }
//pojo实体类deptlog  连接数据库
@Data
@NoArgsConstructor
@AllArgsConstructor
public class DeptLog {
    private Integer id;
    private LocalDateTime createTime;
    private String description;
}
//deptlogservice接口
public interface DeptLogService {
    void insert(DeptLog deptLog);
}
//deptlogservice实体类
@Service
public class DeptLogServiceImpl implements DeptLogService {

    @Autowired
    private DeptLogMapper deptLogMapper;
    @Transactional(propagation = Propagation.REQUIRES_NEW)
    @Override
    public void insert(DeptLog deptLog) {
        deptLogMapper.insert(deptLog);
    }
}
//mapper接口  操作数据库
@Mapper
public interface DeptLogMapper {
    @Insert("insert into dept_log(create_time, description) VALUES (#(createTime),#(description))")
    void insert(DeptLog log);
}

AOP基础

AOP概述

Aspect Oriented Programming        (面向切面编程,面向方面编程)        ,其实就是面向特定方法编程

AOP快速入门 统计各个业务层方法执行耗时

//pom.xml引入依赖
<!--        AOP-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-aop</artifactId>
        </dependency>
//新建包和类
@Slf4j
@Component//交给ioc容器管理,成为bean对象
@Aspect//AOP类
public class TimeAspect {
    @Around("execution(* com.example.springboot.*.*(..))")//切入点表达式
    public Object recordTime(ProceedingJoinPoint joinPoint) throws Throwable {
        //记录开始时间
        long begin = System.currentTimeMillis();
        //调用原始方法运行
        Object result = joinPoint.proceed();
        //记录结束时间,计算方法执行耗时
        long end = System.currentTimeMillis();
        log.info(joinPoint.getSignature()+"方法执行耗时:{}ms",end-begin);
        return result;
    }
}

AOP核心概念

AOP进阶

通知类型

PointCut

@Slf4j
@Component
@Aspect
public class MyAspect1 {
    @Pointcut("execution(* com.example.springboot.service.impl.DeptServiceImpl.*(..))")
    private void pt(){}
    @Before("pt()")
    public void before(){
        log.info("before ...");
    }
    @Around("pt()")
    public  Object around(ProceedingJoinPoint proceedingJoinPoint) throws Throwable {
        log.info("around defore ...");
        //调用原始方法执行
        Object result = proceedingJoinPoint.proceed();
        log.info("around after ...");
        return result;
    }
}

通知顺序

切入点表达式

描述切入点方法的一种表达式

作用:

主要用来决定项目中的哪些方法需要加入通知

常见形式:

execution

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

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

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

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

包名.类名:可省略(不推荐)、

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

可使用通配符描述切入点

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

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

@Pointcut("execution(* com.example.springboot.service.impl.DeptServiceImpl.*(..))")
//根据业务需求,可使用  且(&&) 或(||) 非(!)来组合复杂的切入点表达式
书写建议

方法名在命名时  尽量规范,方便表达式快速匹配

描述切入点方法通常基于接口描述 ,增强拓展性

尽量缩小切入点的匹配范围

@annotation

用于匹配标识有特定注解的方法   注解全类面

//aop新建annotion加上这两个注解
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)//在METHOD上生效
//service上要用的方法上加入
@MyLog
    @Override
    public List<Dept> list(){
        return deptMapper.list();
    }
//要用的方法
@Pointcut("@annotation(com.example.springboot.aop.MyLog)")

连接点

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

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

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

AOP案例  案例中增删改查相关接口操作日志记录到数据库表中

//引入aop的起步依赖 pom中
<dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-aop</artifactId>
        </dependency>
//数据库中新建数据库表结构,并引入实体类放入pojo下,创建mapper方法
//创建注解包anno,新建annotation类型的类(自定义注解@Log)
@Retention(RetentionPolicy.RUNTIME)//运行
@Target(ElementType.METHOD)
//新建切面类
@Slf4j
@Component
@Aspect //切面类
public class LogAspect {
    @Autowired
    private HttpServletResponse request;
    @Autowired
    private OperateLogMapper operateLogMapper;
    @Around("@annotation(com.example.springboot.anno.Log)")
    public Object recordLog(ProceedingJoinPoint joinPoint) throws Throwable {
        //操作人ID -当前登录员工ID
        //获取请求头中的JWT令牌,解析令牌
        String jwt=request.getHeader("token");
        Map<String, Object> claims = JwtUtils.ParseJwt(jwt);
        Integer operateUser= (Integer) claims.get("id");
        //操作时间
        LocalDateTime operateTime=LocalDateTime.now();
        //操作类名
        String className = joinPoint.getTarget().getClass().getName();
        //操作方法名
        String methodName = joinPoint.getSignature().getName();
        //操作方法参数
        Object[] args = joinPoint.getArgs();
        String methodParams = Arrays.toString(args);
        long begin=System.currentTimeMillis();
        //调用原始目标方法运行
        Object result=joinPoint.proceed();
        long end=System.currentTimeMillis();
        //方法返回值
        String returnValue=JSONObject.toJSONString(result);
        //操作耗时
        Long costTime=end-begin;
        //记录操作日志
        OperateLog operateLog = new OperateLog(null,operateUser,operateTime,className,methodName,methodParams,returnValue);
        operateLogMapper.insert(operateLog);
        return result;
    }
}
//controller层中在要加入的内容下
@Log

  • 4
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值