Spring--事务处理编程
Spring事务处理编程
- 事务
- 事务特性(ACID)
- 事务功能
- 事务类型
- 事务控制的位置
- Spring 事务处理API
- AOP编程
- AOP 基础--基本元素
- Spring支持的Advice类型
- Spring AOP 注解类实现方式
- Spring AOP注解类的启用
- Spring AOP编程的过程
- Spring AOP使用AspectJ提供的切面注解类
- Spring AOP切入点的注解类配置
- 各种类型切面Advice的注解类方式实现编程
- Advice的参数
- AOP 事务编程
- Spring 事务处理API
- 什么是脏读、幻读、不可重复读?
事务
Transaction:将多个SQL语句作为一个整体来运行,要么全部提交成功;如果任意一个SQL语句执行失败,则所有SQL语句回滚,回到这些SQL执行之前的状态。
事务特性(ACID)
原子性(Atomicity):
操作这些指令时,要么全部执行成功,要么全部不执行。只要其中一个指令执行失败,所有的指令都执行失败,数据进行回滚,回到执行指令前的数据状态。
拿转账来说,假设用户A和用户B两者的钱加起来一共是20000,那么不管A和B之间如何转账,转几次账,事务结束后两个用户的钱相加起来应该还得是20000,这就是事务的一致性。一致性(Consistency)
事务的执行使数据从一个状态转换为另一个状态,但是对于整个数据的完整性保持稳定。隔离性(Isolation)
隔离性是当多个用户并发访问数据库时,比如操作同一张表时,数据库为每一个用户开启的事务,不能被其他事务的操作所干扰,多个并发事务之间要相互隔离。
即要达到这么一种效果:对于任意两个并发的事务T1和T2,在事务T1看来,T2要么在T1开始之前就已经结束,要么在T1结束之后才开始,这样每个事务都感觉不到有其他事务在并发地执行。持久性(Durability):当事务正确完成后,它对于数据的改变是永久性的。
事务功能
保证系统数据的一致性,防止数据丢失,实现灾难恢复。
假如在一个事务的执行过程中,由于出现意外(如停电),导致部分持久化方法执行,部分没有执行,由于有事务控制,没有执行到事务提交,因此数据库在来电重新启动后,会自动回滚没有提交的事务。
事务类型
本地事务(Local Transaction)
本地事务是操作单一数据资源的事务控制,如操作一个数据库,对其进行增改删操作。一般的项目都是本地事务管理类型。全局事务(Global Transaction)
全局事务是指跨越多个数据资源的事务操作,如同时操作1个MySQL和一个Oracle数据库,一个业务方法中需要同时操作这2个数据库表的情况下。
或者操作一个数据库,又同时操作一个消息队列Kafka, 需要在一个事务控制下。
事务控制的位置
在基于Spring框架 的项目中,事务控制一般在Service层。
因为一个业务方法会涉及到多个持久化方法,必须保证业务方法执行的正确性。
因此在业务层类上或业务方法前,使用@Transactional,而不是在持久层进行事务控制。
Spring 事务处理API
Spring提供了统一的事务处理API来实现各种各样的资源的事务处理,如数据库,消息队列,分布式式事务,消除了各种资源的事务处理的多样性,使用统一的模型和API实现事务处理。
就像JDBC API消除了各种数据库操作的差异性一样,无论各种数据库,如Oracle,MySQL或SQL Server , DB2,通过JDBC API,就可以使用一样的API来操作这些数据库,Java编程的代码是一样的。
Spring也提供了类似的统一化事务API,来处理不同数据资源的事务处理,如使用JDBC操作数据库,使用Hibernate操作数据库,使用MyBatis操作数据库,使用JMS操作消息队列,使用JPA操作数据库,使用JDO操作数据库等等。
MyBatis没有自己的事务控制,而是使用JDBC Connection实现事务控制。
SqlSession session=ssf.openSession();
…
session.commit();
Spring框架提供了统一的事务处理模型API,就是要消除不用框架技术实现事务处理的差异性,而是使用统一的方式实现事务处理。
Spring 的 AOP(面向切面编程)是实现事务处理的最佳模式。
AOP编程
AOP=Aspect Oriented Programming 面向切面编程语言
切面是多个类中的方法中部分重复的代码。
例如对用户增删改查时,只有执行方法(insert,delete)的一行 代码不同,但是四个方法其余相同的代码要写四遍,如果项目中的业务层实现类非常多,需要写大量重复的代码。AOP编程就是要将重复代码集中到一个类里面,抽取出来,简化实现类编程。
AOP 基础–基本元素
通知(Advice)
Advice就是跨越多个类多个方法的重复代码。
我们把这些重复代码截取出来,放在Advice类的方法中。//方法前 <- 切入 public void add(DepartmentModel dm) throws Exception{session.save(dm); } 方法后 <- 切入public void delete(DepartmentModel dm) throws Exception{session.update(dm); } public void delete(DepartmentModel dm) throws Exception{session.delete(dm); } 抽取的重复代码,写到Advice类中就是:class ServiceTXAdvice {public void doHibernateTxwork(){SessionFactory sf=HibernateFactory.createSessionFactory();//创建SessionSession session=sf.openSession();//开启事务Transaction tx=session.beginTransaction();//此处执行目标对象方法 ds.add(dm)//提交事务tx.commit();//关闭sessionsession.close();} }
连接点(Join point)
连接点就是Advice类的方法执行的每个地点。
以上面的部门业务实现类为例,把重复代码都抽取出来,每个就剩下一句不重复的代码
切面Advice的代码执行的连接点是业务实现类对象的方法前和方法后,实现对目标对象方法的环绕。
按照案例,现在Advice的连接点就是部门业务层的add方法前和后,modify方法的前和后, delete方法的前和后等等,还有员工业务层的add方法前和后,modify方法的前和后, delete方法的前和后等等。业务层每个类每个方法的前是一个连接点,后也是一个连接点。Spring AOP只支持方法的调用的连接点,包括方法前,方法后,方法前后,方法异常抛出后。实际项目开发中 95%的应用都是对方法的切入。
Spring AOP不支持如类的载入, 对象的创建,对象的销毁等连接点。
另一个著名的AOP框架 AspectJ全面支持各种各样的连接点,如方法调用, 类的载入, 对象的创建, 对象的销毁。切入点(Pointcut)
在AOP编程中,由于连接点过多,无法实现对每个连接点进行切面的配置。
那就对众多连接点进行分析,找到他们的规律,将多个有相同规律的连接点定义为一个切入点。
切入点就是有相同规律的连接点的集合,表示多个连接点。
如下就是典型的切入点:
(1)所有业务层实现类的所有方法前。
(2)所有业务层实现类的所有方法后。
(3)所有业务层实现类的所有方法前和后。
(4)所有业务层实现类中以get开头的方法的前。
(5)所有在包: com.city.oa.service.impl下的类的所有以get开头的方法前和后。
Spring AOP编程通过定义切入点,将Advice代码,切入到切入点定义的连接点中。切面(Aspect)
切面是Advice和切入点的结合。
一个切面表达: 要切入的代码(Advice中定义)和要切入的地点(切入点)。
也就是做什么,在哪些地方做。
切面编程的核心就是编写Advice代码,再定义切入点, 并启用AOP机制,Spring IoC容器自动创建Advice对象,切入的目标对象,再检查切入点语法,自动将Advice代码切入到指定的连接点执行。目标对象(Target)
目标对象就是切面要切入的类以及他的方法。
将原始包含切面重复代码和不重复代码分离后, 重复代码成为Advice,剩余的不重复代码变成目标对象。
Spring AOP通过整合切面和目标对象,还原成原始的代码状态。代理类(AOP proxy)
Spring实现AOP,是通过创建一个代理对象,将Advice对象 和目标对象 结合在一起,
执行代理对象的方法,完成切面代码和目标代码的共同执行。织入(Weaving)
织入是指Spring框架将切面和目标对象,按照切入点的要求,组装成代理对象的过程。
Spring AOP是动态织入的,即在运行时自动完成。
Spring支持的Advice类型
根据Spring支持的方法调用的连接点位置,Spring AOP支持如下5种类型的Advice。
方法前Advice(Before advice)
在目标对象的方法调用前切入的切面。方法返回后Advice(After returning advice)
当目标对象的方法正常执行,没有异常,并返回后,切入。方法后Advice(After (finally) advice)
当目标对象方法执行结束后切入。即使方法因为抛出异常,没有正常返回,也切入。
这一点是与方法返回后Advice不一样。环绕Advice(Around advice)
环绕是在Advice代码分成2部分,一部分代码在目标对象的方法调用前切入,另一部分代码在目标对象的方法调用后切入。
像业务层案例中的Hibernate API编程就是环绕Advice,在session.save方法前,切入的切面代码完成SessionFactory获取,Session的open,事务的启动,在执行session.save方法后,切入的代码完成事务的提交, session的关闭。方法抛出异常后Advice(After throwing advice)
此切面是在目标对象的方法调用期间出现了异常,我们可以定义要切入的异常类型,当异常类型与定义的异常类型相同时,切面的Advice代码自动启动运行。
Spring AOP 注解类实现方式
Spring AOP模块实现AOP编程是通过集成了著名的AOP框架AspectJ实现的。
目前支持其第5版,即AspectJ 5.
Spring AOP编程的核心是:
- 使用AspectJ的注解类实现Advice类和方法的编程。
- 使用AspectJ的注解类实现切入点的定义和方法的编程。
- Spring IoC容器自动扫描这些注解类修饰的类和方法,自动创建切面类对象,目标对象,代理对象,并执行代理对象的方法,实现切面与目标对象的合成。
依赖库的引入
要在Spring项目中使用AspectJ,需要因为如下依赖类库:
- AspectJ框架的Java类库 aspectjweaver的引入
在项目的pom.xml中加入AspectJ织入类库的依赖
<!-- https://mvnrepository.com/artifact/org.aspectj/aspectjweaver -->
<dependency><groupId>org.aspectj</groupId><artifactId>aspectjweaver</artifactId><version>1.9.5</version>
</dependency>
- AOP aopalliance依赖库: 这是一个AOP组织定义的标准的AOP接口库。
<!-- https://mvnrepository.com/artifact/aopalliance/aopalliance -->
<dependency><groupId>aopalliance</groupId><artifactId>aopalliance</artifactId><version>1.0</version>
</dependency>
Spring AOP注解类的启用
在使用Spring AOP注解类编写AOP之前,需要在Spring IoC容器的配置文件中加入启用 AOP AspectJ 注解类的配置。
1.配置类方式启用 AOP注解类
在使用的Spring配置上加入@EnableAspectJAutoProxy
代码如下:
@Configuration
@ComponentScan(basePackages = { "com.city.oa"})
@EnableAspectJAutoProxy
public class SpringAnnotationConfig {}
2.XML方式配置启用AOP注解类:
在XML的Spring配置文件中加入:<aop:aspectj-autoproxy/>
配置文件 applicationContext.xml 配置内容如下:
<!-- 主配置XML文件 -->
<!-- 扫描使用注解类配置的Bean -->
<context:component-scan base-package="com.city.oa"></context:component-scan>
<!-- 启用AOP注解类 -->
<aop:aspectj-autoproxy />
注意:此标记是定义在aop命名空间中,项目中的Spring XML配置文件已经包含了基本上需要的所有的命名空间。
Spring AOP编程的过程
定义AOP中的Advice类,并使用@Component和@Aspect对Advice进行注解
Spring支持POJO类方式实现Advice,即Advice类不需要实现任何接口,也不需要继承任何父类。普通的类就可以作为Advice。这是Spring新版本的功能,老版本的Spring需要实现Advice的接口,才能实现具体的advice,如方法前,方法后,方法环绕等。
定义的Advice类如下:
//业务Service的AOP Advice类@Component @Aspect public class ServiceLayAdvice {}
在启用Spring容器AspectJ支持的情况下,所有有@Aspect标记的Bean对象都会作为AOP的切面类。
注:Sprring是不允许一个Advice去切入到另一个Advice的,只能切入普通的Bean的方法调用。
定义Advice切面方法。
在Advice类中定义切面方法,如下定义一个方法前的切面代码,只在执行指定目标对象的方法前输出一个字符串,并没有实际意义,但可以演示Advice的使用。@Component @Aspect public class ServiceLayAdvice {//切面方法 public void methodBeforeRun() throws Exception{System.out.println("业务层方法前切面代码执行。。。。");}}
在方法前使用AOP的切入点注解类实现切入点的配置。
Spring AOP支持在Advice方法前面,使用各种类型AspectJ Advice注解类来定义Advice的类型,
如@Before用于配置方法前切面方法,@AfterReturning定义方法返回后切面方法。
增加了Advice类型注解类@Before的代码如下:@Component @Aspect public class ServiceLayAdvice {@Before(value="execution(* com.city.oa.service.impl.*.*(..))")public void methodBeforeRun() throws Exception{System.out.println("业务层方法前切面代码执行。。。。");} }
代码中@Before定义此切面方法为方法前Advice,其中属性value指定了切入点,这里使用了内置切入点定义的语法。下小节专门讲解各种切入点的定义,因为在AOP编程过程中切入点的定义是非常关键的。
value=“execution(* com.city.oa.service.impl..(…))”
上面切入点是使用AspectJ的表达式语法, execution(表达式)是指定运行方法的切入点,
其中:* com.city.oa.service.impl..(…) 表示切入点是com.city.oa.service.impl包下的所有类 的所有方法,参数任意,返回类不限的的方法。这些方法运行时,Spring AOP自动切入Advice类的此方法运行。 因为是@Before,Advice在方法调用前执行。测试
在测试类中调用部门业务层对象的任意方法,这里测试的是取得指定部门的查询方法,AOP的Advice会自动在方法前切入运行。
Spring AOP使用AspectJ提供的切面注解类
@Pointcut
切入点的定义。该注解类修改的方法就是一个切入点,可以被其他切面Advice类引用。@Before
声明方法前Advice切面方法。属性value指定切入点,默认属性,可以省略。@After
方法结束后切面,当方法正常返回或抛出异常返回都切入。@AfterRetruning
方法返回后切面,只有当方法正常返回后,且没有抛出异常才切入。@Around
方法环绕切面,在目标对象方法的执行前切入方法前代码, 方法接收后再切入方法后代码。
环绕切面通常可用于计算方法的执行时间,以及事务处理等。@AfterThrowing
异常抛出后切面,当目标对象的方法执行时抛出异常后,本切面切入运行,一般用于异常日志记录。如出现异常后自动发送Mail,QQ或微信,或写入日志文件。
Spring AOP切入点的注解类配置
在AOP编程中切入点的定义是非常关键的,只有定义了正确的切入点,AOP的Advice类的切面方法才能对指定的目标对象方法进行切入。
Spring AOP通过支持AspectJ的切入点语法实现切入点的定义。
切入点定义:
1.独立切入点定义
此种类型是通过在使用@Aspect注解的切面类中使用@Pointcut定义专门的切入点。
在定义Advice的各种类型的切面方法时,引用@Pointcut定义的切入点方法。
(1)先定义切入点
@Component
@Aspect
public class ServiceAOPPointcut {//定义OA项目所有业务层所有方法执行的切入点@Pointcut("execution(* com.city.oa.service.impl.*.*(..))")public void serviceImplPointcut() {}
}
(2)定义Advice时,引用定义的切入点
//业务Service的AOP Advice类
@Component
@Aspect
public class ServiceLayAdvice {//引入切入点类的指定方法的切入点@Before( value="com.city.oa.aop.ServiceAOPPointcut.serviceImplPointcut()")public void methodBeforeRun() throws Exception{System.out.println("业务层方法前切面代码执行。。。。");}
}
这里:@Before的value值就是切入点类的方法:com.city.oa.aop.ServiceAOPPointcut.serviceImplPointcut()
2.内嵌式切入点
@Component
@Aspect
public class ServiceLayAdvice {//引入切入点类的指定方法的切入点@Before(value="execution(* com.city.oa.service.impl.*.*(..))")public void methodBeforeRun() throws Exception{System.out.println("业务层方法前切面代码执行。。。。");}
}
代码中的@Before的value值直接使用使用了AspectJ的切入点表达式,没有引用切入点类中的切入点方法。
切入点类型的选择,如果切入点多次使用,最好创建切入点类和切入点方法,在各个切面Advice定义中引用即可,如果修改切入点的表达式,只需修改一处,即切入点类的指定切入点方法。
如果切入点就使用一次,可以使用内嵌式语法。毕竟就一个地方,修改也就改一处。
企业级项目中引入切入点需要使用在多个Advice中,还是推荐单独编写切入点类和切入点方法。
切入点类和切入点方法的定义语法
- 切入点类前要使用@Component (让Spring IoC容器能扫描到), @Aspect 进行注释(让Spring IoC容器解析为一个切面类)。
- 在类中定义切面方法,并使用@Pointcut进行注解
(1)方法要求public
(2)方法返回类型是void
(3)方法不能有参数。
(4)方法体无代码。
(5)@Pointcut的属性value中定义切入点表达式。
@Component
@Aspect
public class 切入点类名 {
@Pointcut(value=“切入点表达式”)
public void 切入点方法名() {}
…
}
常用AspectJ的切入点表达式语法
Spring AOP的切入点只支持方法的调用,因此所有切入点的语法的目标都是定位要切入的方法。Spring AOP切入点表达式使用AspectJ 5 pointcut expression语言来完成。
AspectJ 5切入点语言支持如下常用的表达式:
- execution
执行方法的匹配语法,通过正则表达式实现对目标对象方法的匹配。
语法:execution( 表达式)
其中表达式的组成如下: [修饰符模式] 返回类型模式 方法名模式(参数模式) [抛出异常类型模式]
其中使用[]括起来的部分是可以省略的。其他部分不能省略。
返回类型模式:指定方法的返回类型,可以使用* 表达任何返回类型。
方法名模式:指定方法的名称,使用表示任意, .表示包间隔,…表示子包。
参数模式: () 表示一个任意参数, (…) 表示多个任意参数, ()表示无参数, (,String)表示2个参数,第1个任意类型,第2个是String, (int,…) 表示第1参数参数类型是int, 其余参数任意。
execution( 表达式)
表达式= com.city.oa.service.impl..(…)
案例说明:
execution(public * (…)) 指定所有public的任意类的任意方法
execution( set*(…)) 所有类的set开头的方法
execution(* com.city.oa.service.impl..(…)) 包com.city.oa.service.impl下的所有类的所有方法,任意参数均可。
execution(* com.city.oa.service….(…)) 包com.city.oa.service下及子包的所有类的所有方法,任意参数均可。
execution(public List com.city.oa.service.impl..(…)) 包com.city.oa.service.impl下的所有类的所有方法中返回类型是List的方法,任意参数均可
execution(public List<?> com.city.oa.service.impl..(…)) 包com.city.oa.service.impl下的所有类的所有方法中返回类型是List带泛型的方法,任意参数均可
execution(public List com.city.oa.service.impl..get(…)) 包com.city.oa.service.impl下的所有类的所有方法中以get开头的返回类型是List的方法,任意参数均可
@Pointcut(value="execution(* com.city.oa.service..*Impl.*(int,..))") 第1个参数是int类型
@Pointcut(value="execution(* com.city.oa.service..*Impl.*(int))") 只能有1个int参数
@Pointcut(value="execution(* com.city.oa.service..*Impl.*(int,String,..))") @Pointcut(value="execution(public * com.city.oa.service.impl.*.*(..))")
@Pointcut(value="execution(* com.city.oa.service.impl.*.*(..))")@Pointcut(value="execution(public List<?> com.city.oa.service.impl.*.*(..))")@Pointcut(value="execution(* com.city.oa.service..*.*(..))")
@Pointcut(value="execution(* com.city.oa.service..*Impl.*(..))")@Pointcut(value="execution(* com.city.oa.service..*Impl.*(int,..))")
@Pointcut(value="execution(* com.city.oa.service..*Impl.*(int))")
@Pointcut(value="execution(* com.city.oa.service..*Impl.*(int,String,..))")
within
限定指定类型的bean的所有方法。
使用案例:
within(com.city.oa.service…) 包com.city.oa.service包及子包下所有类的方法
实际应用
@Pointcut("within(com.city.oa.service…)")this
指定Bean类型的所有方法,如果指定最好指定为接口类型,不要指定到实现类。
this(com.city.oa.service.IDepartmentService)
使用:
@Pointcut(“this(com.city.oa.service.IDepartmentService)”)target
与this类型,指定固定类型的Bean的所有方法
target(com.city.oa.service.IDepartmentService)
使用:
@Pointcut(“target(com.city.oa.service.IDepartmentService)”)args
指定参数类型的Bean的方法。Spring会在IoC容器中查找所有args指定参数的类的方法。实际使用很少。
args(java.io.Serializable)
args(java.lang.String)
args(int)
使用:
@Pointcut(“args(java.lang.String)”)@target
指定Bean的类前有指定注解类的Bean的所有方法
@target(org.springframework.transaction.annotation.Transactional) 所有使用@Transactional修饰的Bean类。
@target(org.springframework.stereotype.Service) 所有使用@Service修饰的类的所有方法。@args
指定方法中参数前有注解类修饰的方法。
@args(corg.springframework.beans.factory.annotation.Qualifier) 指定参数前有@Qualifier修饰的参数的所有方法。@within
与@target类型,指定有注解类的Bean类的所有方法
@within(org.springframework.transaction.annotation.Transactional)@annotation
指定Spring IoC容器管理的bean的方法前有指定注解类的方法。
@annotation(org.springframework.transaction.annotation.Transactional)
指定方法有@Transactional的所有方法。
各种类型切面Advice的注解类方式实现编程
Spring AOP提供了各种使用在AOP Advice类方法前的注解类实现不同类型的Advice,Spring支持普通的POJO类作为Advice类。
一个Advice类可以包含多个不同的Advice方法。
方法前切面Advice
在Advice方法前使用@Before,完成方法前的定义。该注解类默认的属性value确定切入的切入点。
@Component
@Aspect
public class BeforeExample {@Before("切入点类.切入点方法()")
public void doAccessCheck() {// 切面代码
}
}
@Before也支持嵌入式切入点语法:
@Before(value="execution(* com.city.oa.service.impl.*.*(..))")
public void methodBeforeRun() throws Exception{System.out.println("业务层方法前切面代码执行。。。。");
}
注意:如果不使用注解类扫描方式,如XML配置Bean方式,@Component可以不用,但是@Aspect必须使用,即使使用XML方式配置AOP。
方法返回后切面(After Returning Advice)
使用@AfterReturning实现方法返回后的Advice编程。
案例:
@Component
@Aspect
public class AfterReturningExample {@AfterReturning("com.xyz.myapp.SystemArchitecture.dataAccessOperation()")
public void doAccessCheck() {// ...
}
}
方法返回Advice可以接收切入目标对象方法的返回,如果确实需要取得方法的返回值,可以使用@AfterReturing注解类的returning属性定义advice方法的参数名,并在方法中定义此参数即可,接收方法返回值的类型通常使用Object,可以接收任意类型的方法返回值。
@Aspect
public class AfterReturningExample {@AfterReturning(pointcut="com.xyz.myapp.SystemArchitecture.dataAccessOperation()", returning="retVal")
public void doAccessCheck(Object retVal) {// ...
}
}
记住:returning的值,就是方法的参数名。@AfterReturning也提供了属性pointcut 与属性value都是指定切入点,有的文档和书使用pointcut,这里使用value。
方法后切面(After (Finally) Advice)
方法后切面使用@After注解类修饰Advice方法,实现切入方法的返回后执行,无论是正常返回还是抛出异常返回。此类型Advice无法取得方法的返回值,因为无法确定是方法的正常返回,还是异常返回。
@Aspect
public class AfterFinallyExample {@After("com.xyz.myapp.SystemArchitecture.dataAccessOperation()")
public void doReleaseLock() {// 切面代码
}
}
方法环绕切面(Around Advice)
环绕切面是使用@Around注解类修饰切面方法。
1.环绕方法要求返回Object, 接收目标对象的返回值。
2.环绕切面方法必须接收ProceedingJoinPoint参数,通过该对象的proceed()完成对目标对象的方法的执行。否则目标对象方法无法执行。
3.方法要抛出异常Throwable
4.方法最后需要return result;
环绕切面方法的编程语法如下:
//方法前代码区
Object result=ProceedingJoinPoint对象proceed();
//方法后代码区
return result;
其中:以Object result=ProceedingJoinPoint对象proceed();为界,该语句前是方法前执行的方法,该语句后是目标方法后执行的代码。
Object result=ProceedingJoinPoint对象proceed(); 完成对目标对象方法的执行。
案例语法:
@Aspect
public class AroundExample {@Around("com.xyz.myapp.SystemArchitecture.businessService()")
public Object doBasicProfiling(ProceedingJoinPoint pjp) throws Throwable {// start stopwatch
Object retVal = pjp.proceed();
// stop stopwatch
return retVal;
}
}
方法异常抛出后切面(After Throwing Advice)
方法异常抛出后切面是当切入点匹配的方法抛出异常后执行。
使用注解类@AfterThrowing修改Advice方法, 该注解类使用value或pointcut属性指定切入点,throwing属性指定接收抛出的异常对象。
1.不接收异常对象
@Aspect
public class AfterThrowingExample {@AfterThrowing("com.xyz.myapp.SystemArchitecture.dataAccessOperation()")
public void doRecoveryActions() {// 切面代码
}
}
2.接收异常对象
@Aspect
public class AfterThrowingExample {@AfterThrowing(pointcut="com.xyz.myapp.SystemArchitecture.dataAccessOperation()",
throwing="ex")
public void doRecoveryActions(DataAccessException ex) {// 切面代码
}
}
接收的异常对象类型,可以使用具体的异常,也可以是Exception,甚至是所有的异常类型Throwable。throwing指定的名称,要与方法的参数名一致。
Advice的参数
所有的Advice的方法都可以接收参数,上面我们看到方法返回后Advice接收方法的返回结果, 异常抛出后的Advice接收方法抛出的异常,环绕Advice接收的ProceedingJoinPoint对象。
Advice可以接收的参数的类型:
JoinPoint
所有的Advice都可以接收JoinPoint(org.aspectj.lang.JoinPoint)对象作为第1个参数,此对象可以取得拦截(切入)目标对象的所有信息,包括切入对象的类名称,方法名称,方法的参数等。注意:环绕Advice接收的第1个参数类型是ProceedingJoinPoint,它是JoinPoint的子接口,实际上也是JoinPoint, 但是JoinPoint没有proceed()方法,无法执行目标对象方法,因此环绕Advice必须接收ProceedingJoinPoint类型参数,其他类型Advice接收JoinPoint参数。
JoinPoint提供的方法如下:假如参数 JoinPoint jp:
• getArgs(): 返回方法的参数集合 Object[].
• getThis(): 返回Advice类对象.
• getTarget(): 返回拦截的目标对象.
取得目标对象的类名:jp.getTarget().getClass().getName()
• getSignature(): 返回拦截的目标对象方法
取得切入的方法名: jp.getSignature().getName()
• toString(): 取得切入点信息,
显示案例如下:
execution(DepartmentModel com.city.oa.service.IDepartmentService.getByNo(int))
AOP 事务编程
声明式事务编程(declarative transaction management)
通过配置方式实现事务处理,不需要编写事务处理代码。
Spring内置了事务Advice,不需要编写事务处理代码。
通过设置事务Advice的切入点,并启用Spring事务管理机制,Spring自动将事务应用到目标类的方法。并且新版的Spring通过注解类@Transactional就可以配置事务的切入点,Spring 事务Advice自动切入使用@Transactional注解类注解的类的方法,或直接注解的方法,极大简化了事务的配置。实现方式:
- Spring Java Config配置类 + @Transactional注解类
在Spring Boot流行的情况,使用Java配置类配置Spring IoC管理的Bean对象已经变得非常流行。 - Spring XML配置文件+@Transactional注解类
XML方式配置Spring在公司项目开发中还普遍使用。
虽然新项目的开发已经初步向配置类方向方法,还是有非常多的Spring项目依然使用XML文件配置。 - 纯的XML配置方式
此种方式在新的项目中使用越来越少。
- Spring Java Config配置类 + @Transactional注解类
编程式事务处理(programmatic transaction management)
Spring也支持统一的编程式事务处理,不再需要各自框架自己的事务管理API编程,实现了事务编程的统一模式。
Spring提供了事务编程模块API:TransactionTemplate
Spring 事务处理API
PlatformTransactionManager:通用的事务管理器接口
Spring提供了所有资源事务处理标准的事务处理管理器的接口。
该接口定义了所有类型的资源事务管理器必须提供的功能。
Spring提供了各种资源管理的事务管理器实现类,如Hibernate,JPA,JDO,JDBC,JMS,JTA等,都实现PlatformTransactionManager接口。JDBC的事务接口实现类:
org.springframework.jdbc.datasource.DataSourceTransactionManager
使用在JDBC实现数据库的编程环境下。
MyBaits持久层框架也是使用JDBC模式,也使用此事务管理器实现类,Spring没有提供MyBatis专门的事务管理器。Hibernate的事务接口实现类
org.springframework.orm.hibernate5.HibernateTransactionManager
Hibernate框架使用自己的事务管理API,Spring提供了支持Hibernate5的事务管理实现类。JPA的事务接口实现类
JpaTransactionManagerJMS事务接口实现类
JmsTransactionManager
JTA事务实现类
JtaTransactionManager
TransactionDefinition
事务的定义接口,可以实现各种类型事务的统一属性定义。
通过此接口可以设置不同资源的事务的特性,如事务的隔离级别,传播特性,只读,超时等。TransactionStatus
统一的事务控制接口,定义了各种事务的控制方法。
实现各种资源管理事务的统一控制,如使用TransactionStatus.commit() 可以提交事务,不管使用的是Hibernate,MyBatis,还是JDBC,JTA等等。
什么是脏读、幻读、不可重复读?
脏读 : 一个事务读取到另一事务未提交的更新数据
不可重复读 : 在同一事务中, 多次读取同一数据返回的结果有所不同, 换句话说, 后续读取可以读到另一事务已提交的更新数据. 相反, "可重复读"在同一事务中多次读取数据时, 能够保证所读数据一样, 也就是后续读取不能读到另一事务已提交的更新数据
幻读 : 一个事务读到另一个事务已提交的insert数据
Spring--事务处理编程相关推荐
- Spring切面编程
Spring切面编程 1.导入maven依赖 2.切面实现 2.1.切面@Aspect 2.2.切点@PointCut 2.2.1.execution表达式语法 2.3.切面增强处理Advice声明 ...
- Spring事务处理流程和原理(动脑学院笔记)
一.事务理论 1.事务的特性 2.事务的隔离级别 3.事务的传播 4.利用数据库事务实现应用事务控制 要求:同一个事务需要同一个库的同一个连接. 5.单一数据源,如何让事务的所有操作使用同一连 ...
- java元婴期(20)----java进阶(spring(4)---spring aop编程(全自动)AspectJ)
spring aop编程:全自动[掌握] 从spring容器获得目标类,如果配置aop,spring将自动生成代理. 要确定目标类,aspectj 切入点表达式,导入jar包(maven项目直接导入相 ...
- Spring注解编程基石(一)
目录 Java注解 Java原生注解 元注解 Stereotype 注解 组合注解 组合注解实现的基础 @AliasFor 隐式别名 @AliasFor 和 @Inherited 区别 注解解析工具 ...
- Spring注解编程基石(二)
目录 辅助类 AttributeMethods AnnotationFilter RepeatableContainers MergedAnnotation接口 AnnotationsProcesso ...
- Spring注解编程基石(三)
目录 AnnotationUtils 源码分析 方法列表 方法源码 AnnotatedElementUtils 源码分析 Spring注解编程基石(一) Spring注解编程基石(二) Spring注 ...
- Spring注解编程基石(四)
目录 AnnotationsScanner 扫描方法 扫描source为Class方法 扫描source为Method方法 辅助方法 MergedAnnotationSelector MergedAn ...
- Spring事务处理之 编程式事务 和 声明式事务
对事务概念还不了解的可以先看一下 MySQL事务管理(初步了解) 这篇文章 !!! Spring事务管理学习步骤: 1.掌握Spring事务属性 2.掌握Spring事务核心API 3.掌握Sprin ...
- 设计模式——Spring注解编程模型
文章目录 1. 引言 2. Spring注解编程模型 2.1 元注解(Meta-Annotations) 2.2 Spring模式注解(Stereotype Annotations) 2.3 Spri ...
- Spring核心编程思想
第01章:Spring Framework总览 (12讲) 01.课程介绍.mp4 02.内容综述.mp4 03.课前准备:学习三件套(工具.代码与大脑).mp4 ...
最新文章
- python fun
- 安全观之我见(三):省银之道在预防
- Oracle 表空间的段管理
- 一文搞定Linux shell脚本编程( 史上最全汇总 )
- Kudu 使用注意点
- 使用SoapUI生成wsdl文件客户端(二)
- c语言void nzp,二级C语言考试辅导教程第五章:函数[5]
- HDU 1016 Prime Ring Problem
- spring 中beanFactory和ApplicationContext的区别
- 龙果学院Elasticsearch顶尖高手系列-高手进阶篇完整版
- powerDesign逆向工程Mysql转Oracle
- jxt - 强结构文档数据表示协议
- python 中sample是什么_python中的sample什么意思
- 计算机屏幕的显示分辨率与什么有关,事实:显示器屏幕尺寸和分辨率之间是什么关系?...
- oracle mod函数
- 《Adobe Photoshop CS5中文版经典教程(全彩版)》—第2课2.6节替换图像中的颜色...
- 用PS做淘宝宝贝详情页及如何切图导出
- Laravel实现软删除
- Adobe 及 Acrobat Reader 下载链接(FTP)
- MySQL事务——事务隔离界别,MVCC
热门文章
- Amanda之安装、部署、测试以及优缺点
- 转载:NPOI导出到Excel表格
- ospf v3 及WIN XP ipv6
- OpenCV与AIPCV库——学习笔记(一)
- 问题五十四:怎么用ray tracing画参数方程表示的曲面(2)—— bezier surface
- 左边工具栏 隐藏_203 【Ps基础】 工具栏
- Python实现对nginx日志access.log统计
- 统计某一范围内所有的是K的倍数或者含有K的整数
- Matlab实现Faster-RCNN目标检测
- mysql+索引+rebuild_(solr系列:五) solr定时实时重建索引和增量更新