事务管理 &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 '操作日志表';
相关推荐
wowocpp1 小时前
查看 磁盘文件系统格式 linux ubuntu blkid ext4
linux·数据库·ubuntu
m0_571957582 小时前
Java | Leetcode Java题解之第543题二叉树的直径
java·leetcode·题解
C吴新科4 小时前
MySQL入门操作详解
mysql
魔道不误砍柴功4 小时前
Java 中如何巧妙应用 Function 让方法复用性更强
java·开发语言·python
NiNg_1_2344 小时前
SpringBoot整合SpringSecurity实现密码加密解密、登录认证退出功能
java·spring boot·后端
闲晨4 小时前
C++ 继承:代码传承的魔法棒,开启奇幻编程之旅
java·c语言·开发语言·c++·经验分享
测开小菜鸟5 小时前
使用python向钉钉群聊发送消息
java·python·钉钉
Ai 编码助手6 小时前
MySQL中distinct与group by之间的性能进行比较
数据库·mysql
P.H. Infinity6 小时前
【RabbitMQ】04-发送者可靠性
java·rabbitmq·java-rabbitmq
生命几十年3万天6 小时前
java的threadlocal为何内存泄漏
java