事务管理 &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 '操作日志表';
相关推荐
加油=^_^=4 分钟前
MySQL基础篇的补充
数据库·python·mysql
loveLifeLoveCoding9 分钟前
Java List sort() 排序
java·开发语言
草履虫·15 分钟前
【Java集合】LinkedList
java
AngeliaXue17 分钟前
Java集合(List篇)
java·开发语言·list·集合
世俗ˊ18 分钟前
Java中ArrayList和LinkedList的比较
java·开发语言
zhouyiddd22 分钟前
Maven Helper 插件
java·maven·intellij idea
攸攸太上31 分钟前
Docker学习
java·网络·学习·docker·容器
porkczr36 分钟前
oracle rac多个实例就相当于多个数据库系统程序
数据库·oracle
Milo_K38 分钟前
项目文件配置
java·开发语言
码java的秃头阿姨39 分钟前
SpringBoot设置mysql的ssl连接
spring boot·mysql·ssl