aop即Aspect-Oriented Programming ,面向切面编程。html
可使用xml或者注解的方式在项目中使用aop,以注解为例,通常使用能够引用 AspectJ,本身建立一个类,在类上标注好注解 @Aspect
git
@Aspect
public class LogAspect {}
复制代码
在xml中开启扫描便可找到这个注解github
<aop:aspectj-autoproxy />
复制代码
在代码中创建好对应的Point Cut
spring
@Pointcut("execution(* paxi.maokitty.verify.spring.aop.service.ExecuteService.*(..))")
public void allClassPointCut(){}
复制代码
这里PointCut表达式指定类paxi.maokitty.verify.spring.aop.service.ExecuteService全部方法都是目标对象数据库
创建本身须要执行的方法(advice
)编程
@Before("allClassPointCut()")
public void beforeAspectExecuteService(JoinPoint joinPoint){
LOG.info("beforeAspectExecuteService execute method:{}",new Object[]{joinPoint.getStaticPart().toShortString()});
}
复制代码
便可达到对应的目标,并且这种方式作到了对原有代码的无入侵,体验很好。完整的可运行实例请戳这里bash
此处不讨论分布式事务分布式
事务是数据库执行过程当中的一个逻辑单位,由一个有限的数据库操做序列构成。当事务被提交给了数据库,数据库须要确保该事务中的全部操做都成功完成而且结果被永远保存在数据库中。若是事务中有的操做没有成功的完成,则事务中的全部操做都须要回滚,回到事务执行前的状态,同时,该事务对数据库的其余事务执行没有影响。数据库事务通常拥有如下四个特性
java中操做数据库操做的关键类是 Connection
,它表明了对数据库的一个链接,经过对应的方法
connection.commit()
:执行事务的提交语义con.rollback();
:执行事务的回滚语义 能够控制事务操做spring中最简单的实现只须要直接在要使用事务的类上添加注解 @Transactional
,并在xml中添加注解的扫描<tx:annotation-driven transaction-manager="txManagerTest"/>
基本就能够利用spring的事务了
spring对事务的实现则是经过aop来实现的。spring在扫描tx标签的时候,碰到transactional标注的类或者方法,会建立对应的AOP代理,在调用的时候则是AOP代理去执行,先按照AOP的方式执行相应的逻辑,再执行用户定义的方法,若是有问题则执行对应的事务
@Trace(
index = 13,
originClassName = "org.springframework.transaction.interceptor.TransactionAspectSupport",
function = "protected Object invokeWithinTransaction(Method method, @Nullable Class<?> targetClass,final InvocationCallback invocation) throws Throwable"
)
public void invokeWithinTransaction(){
//...
Code.SLICE.source("final TransactionAttribute txAttr = (tas != null ? tas.getTransactionAttribute(method, targetClass) : null);")
.interpretation("查到对应方法的事务配置");
Code.SLICE.source("final PlatformTransactionManager tm = determineTransactionManager(txAttr);")
.interpretation("拿到transactionManager,好比用户在xml中配置的 org.springframework.jdbc.datasource.DataSourceTransactionManager");
Code.SLICE.source("final String joinpointIdentification = methodIdentification(method, targetClass);")
.interpretation("获取transaction标注的方法");
//...
Code.SLICE.source("TransactionInfo txInfo = createTransactionIfNecessary(tm, txAttr, joinpointIdentification);\n" +
" Object retVal = null;\n" +
" try {\n" +
" retVal = invocation.proceedWithInvocation();\n" +
" }\n" +
" catch (Throwable ex) {\n" +
" // target invocation exception\n" +
" completeTransactionAfterThrowing(txInfo, ex);\n" +
" throw ex;\n" +
" }\n" +
" finally {\n" +
" cleanupTransactionInfo(txInfo);\n" +
" }\n" +
" commitTransactionAfterReturning(txInfo);\n" +
" return retVal;")
.interpretation("这里就是标准的事务处理流程 1:获取事务;2:执行用户本身的方法;3:若是执行过程当中抛出了异常执行异常抛出后的事务处理逻辑 4:清除事务信息 5:提交事务");
//...
}
复制代码
这里就注意到 所谓 物理事务 和 逻辑事务的区别
- 物理事务就是底层数据库提供的事务支持
- 逻辑事务则是spring本身管理的事务,它与物理事务最大的区别就在于事务的传播行为,即多个事务在方法间调用时,事务是如何传播的
事务的隔离机制与传播机制源码注解解释各自含义,实际就是Connection的定义
对不一样的隔离机制,也就产生了 脏读、不可重复读、幻读的场景
Y表示会存在,N表示不存在
实质上就是在不一样隔离机制下,多个事务读取数据的影响
spring自定义的传播机制,实际上就是代码的处理逻辑,在不一样的场景下作出的限制
if (definition.getPropagationBehavior() == TransactionDefinition.PROPAGATION_NEVER) {
throw new IllegalTransactionStateException(
"Existing transaction found for transaction marked with propagation 'never'");
}
复制代码
它底层去提交事务或是回滚事务,本质上仍是java的Connection来最终执行操做,另外对于对于一次访问的多个数据库的事务操做,spring本身将链接与线程创建了关联关系,即每一个线程都持有的是同一个链接,来保证指望相同的数据库操做在同一个事务里面。源码的详细追踪实例能够戳这里
个人博客即将同步至腾讯云+社区,邀请你们一同入驻:cloud.tencent.com/developer/s…