IT笔记java事务管理+AOP记录技术
何平安项目文件在之前的公司管理系统上增添的….
—事务管理—
事务是一组操作的集合,它是一个不可分割的工作单位,这些操作要么同时成功,要么同时失败。
简单案例:删除部门,同时删除该部门下的员工。
直接在删除部门方法的Service类下添加个删除员工的方法并在EmpMapper里添加删除对应部门员工的方法。
如果想在让处理的事件回滚并报错,比如在DeptService里删除方法里,添加上@Transactional(rollbackFor = Exception.class),这里的rollbackFor指出现什么异常就回滚,这里是所有异常。为了测试就直接在方法里面的删除部门的deptMapper方法下编写:
1 2 3
| if (true){ throw new Exception("出差啦.."); }
|
这时候再去删除部门就会报错,并且部门也删除不了
事务传播行为:比如要记录比较重要的操作时,如删除部门,无论成功还是失败都要记录日志。这时就再创建一个数据库用于记录日志。在DeptService删除方法下调用添加日志的方法,然后在DeptLogService类下的添加的日志方法下required:大部分情况下都是用该传播行为即可;requires_new:当不希望事务之间相互影响
DeptLogServiceImpl类里面:
1 2 3 4 5 6 7 8 9 10 11
| @Service public class DeptLogServiceImpl implements DeptLogService { @Autowired private DeptLogMapper deptLogMapper;
@Transactional(propagation = Propagation.REQUIRES_NEW) @Override public void insertLog(DeptLog deptLog) { deptLogMapper.insert(deptLog); } }
|
—AOP—
Aspect Oriented Programming,面向切面编程,这里主要编写用于记录日志。
先pom.xml导入AOP的依赖:
1 2 3 4
| <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-aop</artifactId> </dependency>
|
快速入门程序:统计各个业务层方法执行耗时。
@Slf4j
@Component
@Aspect//表示这是一个AOP类
public class TimeAspect {
@Around(“execution(* top.hepingan.service..(..))“) //切入点表达式
public Object recordTime(ProceedingJoinPoint proceedingJoinPoint) throws Throwable {
//记录开始时间
long begin=System.currentTimeMillis();
//调用原始方法运行
Object result=proceedingJoinPoint.proceed();
//记录结束时间 l
ong end=System.currentTimeMillis();
log.info(proceedingJoinPoint.getSignature()+“方法执行耗时:{}ms”,end–begin);
return result; }
}
@Around(“execution(* top.hepingan.service..(..))”)环绕通知注解表示包括service层下的所有业务都要使用这个方法
直接通过案例来:先添加一个数据库表用于存储日志:
1 2 3 4 5 6 7 8 9 10 11
| -- 操作日志表 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 '操作日志表';
|
然后再在pojo里创建一个Operate(操作的意思)类:用于定义数据库里面所有的列,并加上@Data等lombok注解。
然后再在top.hepingan下创建一个注解:anno.Log,里面编写:
1 2 3 4
| @Target(ElementType.METHOD) @Retention(RetentionPolicy.RUNTIME) public @interface Log { }
|
接着在Mapper里面创建OperateLogMapper,编写的代码就是将传递的日志数据添加到数据库:
1 2 3
| @Insert("insert into operate_log (operate_user, operate_time, class_name, method_name, method_params, return_value, cost_time) " + "values (#{operateUser}, #{operateTime}, #{className}, #{methodName}, #{methodParams}, #{returnValue}, #{costTime});") public void insert(OperateLog log);
|
然后再在aop里面创建一个LogAspect:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39
| @Aspect @Component @Slf4j public class LogAscpect { @Autowired private OperateLogMapper operateLogMapper; @Autowired private HttpServletRequest httpServletRequest;
@Around("@annotation(top.hepingan.anno.Log)") public Object recordLog(ProceedingJoinPoint proceedingJoinPoint) throws Throwable {
String jwt=httpServletRequest.getHeader("token"); Claims claims= JwtUtils.parseJWT(jwt); Integer operateUser =(Integer) claims.get("id");
LocalDateTime operateTime=LocalDateTime.now();
String className=proceedingJoinPoint.getTarget().getClass().getName();
String methodName=proceedingJoinPoint.getSignature().getName();
Object[] args=proceedingJoinPoint.getArgs(); String methodParams= Arrays.toString(args);
long begin=System.currentTimeMillis();
Object result=proceedingJoinPoint.proceed();
String returnValue= JSONObject.toJSONString(result);
long end=System.currentTimeMillis(); 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; } }
|
都有注释直接看就行,就是把数据库中的每一个对应的参数都写出来。
我们的目的是在增删改操作后都输出一段日志到数据库中,这时就直接在各个增删改方法上添加上@Log注解。
冷知识:学Java要掌握的英语单词还有点多:[Java程序员必背英语单词70个_编写背单词程序java_✪龍行天下✪的博客-CSDN博客](https://blog.csdn.net/a313970281/article/details/79775819#:~:text=Java程序员必背英语单词70个 1 Compile%3A编绎 2 Run%3A运行 3 Class%3A类 4,System%3A系统 6 out%3A输出 7 print%3A打印 8 line%3A行 更多项目)
配置文件优先级:properties>yml>yaml,在企业开发中,yml为目前的主流。cmd命令行参数级优先级要高于JAVA系统参数级
—Bean的管理—
从IOC容器获取bean
springboot启动时会自动创建bean对象,获取bean对象三种方法:
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| @Test public void testBean(){ //根据bean的名称获取 DeptController bean1= (DeptController) applicationContext.getBean("deptController"); System.out.println(bean1);
//根据bean的类型获取 DeptController bean2= applicationContext.getBean(DeptController.class ); System.out.println(bean2);
//根据bean 的名称及类型获取 DeptController bean3 =applicationContext.getBean("deptController", DeptController.class); System.out.println(bean3); }
|
运行后可以发现输出的bean对象都是一样的,这就说明默认只创建了一个实例对象。
bean的作用域
主要的作用域:singletion:容器内同 名称 的bean 只有一个实例(默认);prototype每次使用该bean时会创建新的实例.
@Lazy注解可以延缓初始化,延迟到第一次使用的时候
设置作用域注解:在DeptController上创建主机呃呃:**@Scope(“prototype”)**,这时再运行bean就不一样了。
第三方类bean(了解)
在配置类使用@Bean注解
—SpringBoot原理—
底层原理有两个,一个是起步依赖,一个是自动配置。
起步依赖就是导入最高级的jar包,然后通过Maven传递依赖的包,就把整个springboot的依赖导入进来了。