你们对事务的基本原理理解了没有,事务的整个原理,声明式事务的原理,就相当于我完全自动化的,他自动通过
扫包或者注解,给我进行实现的,这种方式我们都叫做声明式的,还是不够底层,封装的还不够好,今天就有点难度了,
所以你们待会要认真听一下,任何声明事务,他都是基于编程事务进行实现出来的,声明事务他分为两种,第一种我们
称为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;
}
}