自定义注解事务课程回顾

    xiaoxiao2024-11-28  75

    你们对事务的基本原理理解了没有,事务的整个原理,声明式事务的原理,就相当于我完全自动化的,他自动通过 扫包或者注解,给我进行实现的,这种方式我们都叫做声明式的,还是不够底层,封装的还不够好,今天就有点难度了, 所以你们待会要认真听一下,任何声明事务,他都是基于编程事务进行实现出来的,声明事务他分为两种,第一种我们 称为xml方式,xml方式你们可以这样去理解,加一个扫包范围,然后在这个扫包范围里面,你可以去开启一个事务, 有没有印象,我记得我那会我刚学Spring的时候,比如我在com.learn.service这个包下面,只要有get,save方法, 我们都会加事务,然后在这里还有一个注解版本的,那么我们今天讲个比较难的,就是以什么配置开头的,这种属于xml 方式,什么以add开头,以save开头的我就开启事务,以get开头的,我就不给他开启事务,这种配置比较老了,一般我们 记住啊,因为你们在今后的时候都会学到,比如举个例子,save*星号,update*星号,insert*星号,有没有印象,通过方法名 进行区分事务,还有一种事务你们是绝对用过的,叫做注解版本的,你们用过@Transaction注解没有,这是不是注解版本的, 然后我加到方法里面去的时候,我就表示方法开启这个事务,今天讲一下这个底层是怎么实现的,为什么我要加上一个注解, 能够帮我去做事务管理,有没有人能告诉我他的原理是什么,我们今天讲的有点难度,写代码量有点大,为什么在方法上加入 @Transaction注解的时候,他能够开启事务,你们要知道原理,我点进去,什么都没有,没有源代码,这个其实我告诉你们, 其实怎么做的呢,其实我们今天讲什么原理呢,就是我们自己写一个事务注解出来,然后实现@Transaction一模一样的功能, 完全一模一样的功能,但是我们可能没有时间玩,我们上课时间也有限,具体功能你们下课自己去玩一下,这个思路是我 自己想的,不是说我看过他源码怎么做,因为我不喜欢看别人源码,因为我不看你源码我也能实现你的效果,所以我在 这里讲一下,你们学任何技术的时候,别人代码怎么写的时候,我就抄过来,那就没意义,要有自己的一套思路,这就叫编程思想, 所以在这边,再说一句话,叫编程思想,今后我们的HashMap和HashSet,分布式事务框架,都是按照我们自己的思路写的, 和别人的代码写的有差别,但是最终都达到一个效果,那么今天我们同学可能也知道,我们今天要实现一个自定义注解出来, 实现他的一个效果,那么什么效果呢,比如我现在加一个注解,这个注解我自己写的,叫@ExtTrasaction注解,这个注解是我 自己写出来的,只要加上这个注解之后,那么我就可以在这个方法之前和之后做一个事务管理机制,不知道你们有没有用过 lcn框架没有,他在里面是不是有这样的一种功能,需要在发起方加入一个注解,要在发起方的方法上加一个注解,这个注解 可以解决一个分布式问题,是不是这样的,他使用的也是自定义注解,那他这个是怎么进行实现的呢,我们大致看一下源码 好吧 package com.learn.annotation; import java.lang.annotation.ElementType; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; //事务注解 设置传播行为 @Target({ ElementType.METHOD }) @Retention(RetentionPolicy.RUNTIME) public @interface ExtTransaction { } package com.learn.transaction; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.annotation.Scope; import org.springframework.jdbc.datasource.DataSourceTransactionManager; import org.springframework.stereotype.Component; import org.springframework.transaction.TransactionStatus; import org.springframework.transaction.interceptor.DefaultTransactionAttribute; /** * 我们把事务utils改成原型模式 * 就是一个线程安全的 * 每个事务都是一个单独的实例 * 这样就可以解决一个高并发的一个线程安全问题 * * @author Leon.Sun * */ //编程事务(需要手动begin 手动回滚 手都提交) @Component @Scope("prototype") // 每个事务都是新的实例 目的解决线程安全问题 多例子 public class TransactionUtils { // 全局接受事务状态 private TransactionStatus transactionStatus; // 获取事务源 @Autowired private DataSourceTransactionManager dataSourceTransactionManager; // 开启事务 public TransactionStatus begin() { System.out.println("开启事务"); transactionStatus = dataSourceTransactionManager.getTransaction(new DefaultTransactionAttribute()); return transactionStatus; } // 提交事务 public void commit(TransactionStatus transaction) { System.out.println("提交事务"); dataSourceTransactionManager.commit(transaction); } // 回滚事务 public void rollback() { System.out.println("回滚事务..."); dataSourceTransactionManager.rollback(transactionStatus); } } package com.learn.aop; import java.lang.reflect.Method; import org.aspectj.lang.ProceedingJoinPoint; import org.aspectj.lang.annotation.AfterThrowing; import org.aspectj.lang.annotation.Around; import org.aspectj.lang.annotation.Aspect; import org.aspectj.lang.reflect.MethodSignature; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component; import org.springframework.transaction.TransactionStatus; import com.learn.annotation.ExtTransaction; import com.learn.transaction.TransactionUtils; //自定义事务注解具体实现 /** * 我自己做了一个封装 * 也是通过代理设计模式去拦截 * 为什么代理设计模式也会拦截到注解呢 * 这个待会我讲一下底层的实现原理 * 你就知道是怎么做的 * 这段代码就可以自定注解 * 然后实现我对事物的一个管理 * 其实这个大体不是很难 * 但是我为什么要讲这个呢 * 我觉得大家要学会一种思想 * 以后你们一听就说 * 我们今天要手写一个@Transaction注解出来 * 举得这个我不会 * 这个很高大上 * 那么我告诉你一下 * 当你学完以后会发现 * 这个东西没什么难的 * 就是没什么了不起的 * 就是这样的 * 你会了以后眼界就完全不一样了 * 这个我可以直说的 * 我这边给大家说一下 * 你们下去的时候自己去看一下一些源码 * 也可以下去看一下 * 我提前说几个任务 * 最好下去大致去了解一下 * 我们接下来马上要讲到了 * 你们自己下去去研究一下原理 * 你可以去百度上找个文章 * 去看一下ArrayList是怎么实现的 * 但是我是这么觉得的 * 我觉得最难的一个知识是在哪里呢 * 一个是手写集合框架 * 一个是手写数据库连接池 * 这两个是比较难的 * 可以去网上看一下有没有写数据库连接池 * 我大体把思路告诉你们 * 你们去预习一下 * 否则你们当天会觉得有点抽象 * 连接池的实现原理 * 其实数据库连接池的原理 * 和线程池原理一模一样 * 里面也是用到了并发 * 到时候我们讲手写ORM框架的时候 * 就是实现一个简单版的数据库连接池 * 做一个注解版本的ORM映射 * 映射到表里面自动生成一个SQL语句 * 就是类似于一个hibernate语句 * 最后分享一下mybatis的api * 所以呢我们就不会讲到API了 * 然后HashMap是我觉得比较难的 * 要学这个数据结构 * 像红黑树啊 * 链表 数组 * 这些数据结构 * 所以这两个可能是你们觉得最难的那个 * 然后后序的时候 * 尤其是我们分布式微服务讲完的时候 * 然后就会讲到分布式事务的一个框架 * 我们当天就写一个框架出来 * 你写出来的时候你对分布式事务的眼界 * 绝对是不一样的 * 就是一个大的亮点 * 我们到时候会手写RPC * 这个手写SpringCloud会简单点 * 写dubbo会比较难一点 * 因为SpringCloud是基于http的 * 底层是通过http封装起来的 * 所以这个就比较简单了 * 然后TOMCAT就稍微有点难度了 * 基于多线程加线程池 * netty框架加NIO * 主要是写一个request和响应出来就OK了 * 我们大概要讲两个信息 * 大概讲到月底把整个源码讲完 * 这可能有点难度 * 代码量也比较大 * 大家最好是打一遍 * 不要听我上课讲 * 一定要去敲一遍 * * * * * @author Leon.Sun * */ @Aspect @Component public class AopExtTransaction { // 一个事务实例子 针对一个事务 @Autowired private TransactionUtils transactionUtils; // 使用异常通知进行 回滚事务 @AfterThrowing("execution(* com.learn.service.*.*.*(..))") public void afterThrowing() { // 获取当前事务进行回滚 // TransactionAspectSupport.currentTransactionStatus().setRollbackOnly(); transactionUtils.rollback(); } // 环绕通知 在方法之前和之后处理事情 @Around("execution(* com.learn.service.*.*.*(..))") public void around(ProceedingJoinPoint pjp) throws Throwable { // 1.获取该方法上是否加上注解 ExtTransaction extTransaction = getMethodExtTransaction(pjp); TransactionStatus transactionStatus = begin(extTransaction); // 2.调用目标代理对象方法 pjp.proceed(); // 3.判断该方法上是否就上注解 commit(transactionStatus); } private TransactionStatus begin(ExtTransaction extTransaction) { if (extTransaction == null) { return null; } // 2.如果存在事务注解,开启事务 return transactionUtils.begin(); } private void commit(TransactionStatus transactionStatus) { if (transactionStatus != null) { // 5.如果存在注解,提交事务 transactionUtils.commit(transactionStatus); } } // 获取方法上是否存在事务注解 private ExtTransaction getMethodExtTransaction(ProceedingJoinPoint pjp) throws NoSuchMethodException, SecurityException { String methodName = pjp.getSignature().getName(); // 获取目标对象 Class<?> classTarget = pjp.getTarget().getClass(); // 获取目标对象类型 Class<?>[] par = ((MethodSignature) pjp.getSignature()).getParameterTypes(); // 获取目标对象方法 Method objMethod = classTarget.getMethod(methodName, par); ExtTransaction extTransaction = objMethod.getDeclaredAnnotation(ExtTransaction.class); return extTransaction; } }

     

    最新回复(0)