事务管理 &AOP

一、Spring事务管理

1.@Transactional//Spring 事务管理

2.事务进阶

1.事务属性-回滚(rollbackFor)

2.传播属性(propagation)

1.DeptLog日志对象

java 复制代码
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;

import java.time.LocalDateTime;

@Data
@NoArgsConstructor
@AllArgsConstructor
public class DeptLog {
    private Integer id;
    private LocalDateTime createTime;
    private String description;
}

2.DeptService层

java 复制代码
    /**
     * 根据ID删除部门
     * @param id
     */
    @Transactional(rollbackFor = Exception.class)//Spring 事务管理
    @Override
    public void delete(Integer id) throws Exception {
        try {
            deptMapper.delete(id);
            empMapper.deleteByDeptId ( id );//根据部门Id删除该部门的员工
        int i= 1/0;
//        if (true){
//            throw new Exception ("出错啦");
//        }

        } finally {
            DeptLog deptLog =new DeptLog ();
            deptLog.setCreateTime ( LocalDateTime.now () );
            deptLog.setDescription ( "执行了解散部门的操作,此次解散的是"+id+"号部门" );
            deptLogService.insert ( deptLog );

        }

3.DeptLogService层

java 复制代码
import com.itheima.mapper.DeptLogMapper;
import com.itheima.pojo.DeptLog;
import com.itheima.service.DeptLogService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;

@Service
public class DeptLogServiceImpl implements DeptLogService {

    @Autowired
    private DeptLogMapper deptLogMapper;

    @Transactional(propagation = Propagation.REQUIRES_NEW)
    @Override
    public void insert(DeptLog deptLog) {
        deptLogMapper.insert(deptLog);
    }
}

4.DeptLogMapper层

java 复制代码
import com.itheima.pojo.DeptLog;
import org.apache.ibatis.annotations.Insert;
import org.apache.ibatis.annotations.Mapper;

@Mapper
public interface DeptLogMapper {

    @Insert("insert into dept_log(create_time,description) values(#{createTime},#{description})")
    void insert(DeptLog log);

}

5.数据库层

sql 复制代码
create table dept_log(
   	id int auto_increment comment '主键ID' primary key,
    create_time datetime null comment '操作时间',
    description varchar(300) null comment '操作描述'
)comment '部门操作日志表';

二、AOP-面向切面编程

1.AOP基础

java 复制代码
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.springframework.stereotype.Component;
@Slf4j
@Component
@Aspect//AOP类
public class TimeAspect {
    @Around ( "execution(* com.itheima.service.*.*(..))" )//切入点表达式
    public Object recordTime(ProceedingJoinPoint joinPoint) throws Throwable {
        //1.记录开始时间
        long begin = System.currentTimeMillis ();
        //2.调用原始方法运行
        Object result = joinPoint.proceed ();

        //3.记录结束时间,计算方法执行耗时
        long end = System.currentTimeMillis ();
        log.info (joinPoint.getSignature ()+ "方法执行耗时:{}ms",end-begin );
        return result;
    }
}

2.AOP核心概念

1.概念

2.AOP的执行流程

3.AOP进阶

1.通知类型

java 复制代码
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.*;
import org.springframework.stereotype.Component;

@Slf4j
@Aspect
@Component
    public class MyAspect1 {
    //抽取切入点表达式
    @Pointcut("execution(* com.itheima.service.impl.DeptServiceImpl.*(..))")
    public void p(){}
    @Before ("p()" )
    public void before(){
        log.info ( "before..." );
    }
    @Around ( "p()" )
    public Object around(ProceedingJoinPoint joinPoint) throws Throwable {
        log.info ( "around before..." );
        //调用目标对象的原始方法执行
        Object result = joinPoint.proceed ();
        log.info ( "around..." );
        return result;
    }
    @After ("p()"  )
    public void after(){
            log.info ( "after..." );
    }
    @AfterReturning("p()")
    public void afterReturning(){
            log.info ( "afterReturning..." );
    }
    @AfterThrowing("p()")
    public void afterThrowing(){
            log.info ( "afterThrowing" );
    }
}

2.通知的执行顺序

3.切入点表达式

1.execution(.....)
2.@annotation

4.连接点

java 复制代码
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
import org.springframework.stereotype.Component;

import java.util.Arrays;

//切面类
@Slf4j
@Aspect
@Component
public class MyAspect8 {

    @Pointcut("execution(* com.itheima.service.DeptService.*(..))")
    private void pt(){}

    @Before("pt()")
    public void before(JoinPoint joinPoint){
        log.info("MyAspect8 ... before ...");
    }

    @Around("pt()")
    public Object around(ProceedingJoinPoint joinPoint) throws Throwable {
        log.info("MyAspect8 around before ...");

        //1. 获取 目标对象的类名 .
        String className = joinPoint.getTarget().getClass().getName();
        log.info("目标对象的类名:{}", className);

        //2. 获取 目标方法的方法名 .
        String methodName = joinPoint.getSignature().getName();
        log.info("目标方法的方法名: {}",methodName);

        //3. 获取 目标方法运行时传入的参数 .
        Object[] args = joinPoint.getArgs();
        log.info("目标方法运行时传入的参数: {}", Arrays.toString(args));

        //4. 放行 目标方法执行 .
        Object result = joinPoint.proceed();

        //5. 获取 目标方法运行的返回值 .
        log.info("目标方法运行的返回值: {}",result);

        log.info("MyAspect8 around after ...");
        return result;
    }
}

三、AOP综合案例

1.引入依赖

XML 复制代码
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-aop</artifactId>
        </dependency>

2.设置自定义注解

java 复制代码
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

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

3.日志类对象

java 复制代码
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;

import java.time.LocalDateTime;

@Data
@NoArgsConstructor
@AllArgsConstructor
public class OperateLog {
    private Integer id; //ID
    private Integer operateUser; //操作人ID
    private LocalDateTime operateTime; //操作时间
    private String className; //操作类名
    private String methodName; //操作方法名
    private String methodParams; //操作方法参数
    private String returnValue; //操作方法返回值
    private Long costTime; //操作耗时
}

4.AOP类

java 复制代码
import com.alibaba.fastjson.JSONObject;
import com.itheima.mapper.OperateLogMapper;
import com.itheima.pojo.OperateLog;
import com.itheima.utils.JwtUtils;
import io.jsonwebtoken.Claims;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import javax.servlet.http.HttpServletRequest;
import java.time.LocalDateTime;
import java.util.Arrays;

@Component
@Aspect//切面类
@Slf4j
public class LogAspect {
    @Autowired
    private HttpServletRequest request;
    @Autowired
    private OperateLogMapper operateLogMapper;
    @Around ( "@annotation(com.itheima.anno.Log)" )
    public Object recordLog(ProceedingJoinPoint joinPoint) throws Throwable {


        //操作人ID 当前登录员工的ID (从令牌中获取信息)
        //获取请求头当中的令牌,解析令牌
        String jwt = request.getHeader ( "token" );
        Claims 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,costTime);
        operateLogMapper.insert ( operateLog );
        log.info ( "AOP记录操作日志:{}",operateLog );
        return result;

    }
}

5.数据库表

sql 复制代码
-- 操作日志表
create table operate_log(
    id int unsigned primary key auto_increment comment 'ID',
    operate_user int unsigned comment '操作人ID',
    operate_time datetime comment '操作时间',
    class_name varchar(100) comment '操作的类名',
    method_name varchar(100) comment '操作的方法名',
    method_params varchar(1000) comment '方法参数',
    return_value varchar(2000) comment '返回值',
    cost_time bigint comment '方法执行耗时, 单位:ms'
) comment '操作日志表';
相关推荐
.Bryce.1 小时前
你了解 Blackboard(黑板系统)吗?听说过基于黑板系统实现的智能体吗?
java·网络·gpt·php·agent·codex·黑板系统
草莓熊Lotso3 小时前
【C++ 基于微服务的即时通讯系统】etcd + brpc 从安装到服务注册发现全链路实战
网络·数据库·c++·redis·微服务·etcd
猿究院_夏燊8 小时前
Spring Bean 生命周期
java·后端·spring
Wang's Blog8 小时前
Java 项目实战: 交友项目:登录链路回顾与今日任务地图
java·开发语言·状态模式·交友
信誓旦旦的程序猿9 小时前
【Python量化实战宝典 #08】可转债与债券接口手册:转股价·溢价率·纯债价值(Python 可跑)
java·python·股票数据api·股票数据api接口·股票api数据接口·股票量化数据api·股票量化数据接口
Lethehong9 小时前
Oracle 加个字段,目标库就报错?KFS 用“先拆后组“打通异构 DDL
数据库·oracle
砚底藏山河9 小时前
python量化:行情数据回溯
java·开发语言·python·金融·maven
Jlzn88889 小时前
华东电芯分选通道数怎么配才不堵线
java·人工智能·架构·自动化·制造
Web极客码9 小时前
锁定真正的磁盘卡顿:我用 OpenCode 配合 eBPF 诊断 NVMe 队列深度延迟与 I/O 写放大
数据库·oracle
香吧香9 小时前
GRPC连接机制---长连接分析
java·网络与传输协议