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)

  1. 原子性(Atomicity):
    操作这些指令时,要么全部执行成功,要么全部不执行。只要其中一个指令执行失败,所有的指令都执行失败,数据进行回滚,回到执行指令前的数据状态。
    拿转账来说,假设用户A和用户B两者的钱加起来一共是20000,那么不管A和B之间如何转账,转几次账,事务结束后两个用户的钱相加起来应该还得是20000,这就是事务的一致性。

  2. 一致性(Consistency)
    事务的执行使数据从一个状态转换为另一个状态,但是对于整个数据的完整性保持稳定。

  3. 隔离性(Isolation)
    隔离性是当多个用户并发访问数据库时,比如操作同一张表时,数据库为每一个用户开启的事务,不能被其他事务的操作所干扰,多个并发事务之间要相互隔离。
    即要达到这么一种效果:对于任意两个并发的事务T1和T2,在事务T1看来,T2要么在T1开始之前就已经结束,要么在T1结束之后才开始,这样每个事务都感觉不到有其他事务在并发地执行。

  4. 持久性(Durability):当事务正确完成后,它对于数据的改变是永久性的。

事务功能

保证系统数据的一致性,防止数据丢失,实现灾难恢复。
假如在一个事务的执行过程中,由于出现意外(如停电),导致部分持久化方法执行,部分没有执行,由于有事务控制,没有执行到事务提交,因此数据库在来电重新启动后,会自动回滚没有提交的事务。

事务类型

  1. 本地事务(Local Transaction)
    本地事务是操作单一数据资源的事务控制,如操作一个数据库,对其进行增改删操作。一般的项目都是本地事务管理类型。

  2. 全局事务(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 基础–基本元素

  1. 通知(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();}
    }
    
  2. 连接点(Join point)
    连接点就是Advice类的方法执行的每个地点。
    以上面的部门业务实现类为例,把重复代码都抽取出来,每个就剩下一句不重复的代码
    切面Advice的代码执行的连接点是业务实现类对象的方法前和方法后,实现对目标对象方法的环绕。
    按照案例,现在Advice的连接点就是部门业务层的add方法前和后,modify方法的前和后, delete方法的前和后等等,还有员工业务层的add方法前和后,modify方法的前和后, delete方法的前和后等等。业务层每个类每个方法的前是一个连接点,后也是一个连接点。

    Spring AOP只支持方法的调用的连接点,包括方法前,方法后,方法前后,方法异常抛出后。实际项目开发中 95%的应用都是对方法的切入。

    Spring AOP不支持如类的载入, 对象的创建,对象的销毁等连接点。
    另一个著名的AOP框架 AspectJ全面支持各种各样的连接点,如方法调用, 类的载入, 对象的创建, 对象的销毁。

  3. 切入点(Pointcut)
    在AOP编程中,由于连接点过多,无法实现对每个连接点进行切面的配置。
    那就对众多连接点进行分析,找到他们的规律,将多个有相同规律的连接点定义为一个切入点。
    切入点就是有相同规律的连接点的集合,表示多个连接点。
    如下就是典型的切入点:
    (1)所有业务层实现类的所有方法前。
    (2)所有业务层实现类的所有方法后。
    (3)所有业务层实现类的所有方法前和后。
    (4)所有业务层实现类中以get开头的方法的前。
    (5)所有在包: com.city.oa.service.impl下的类的所有以get开头的方法前和后。
    Spring AOP编程通过定义切入点,将Advice代码,切入到切入点定义的连接点中。

  4. 切面(Aspect)
    切面是Advice和切入点的结合。
    一个切面表达: 要切入的代码(Advice中定义)和要切入的地点(切入点)。
    也就是做什么,在哪些地方做。
    切面编程的核心就是编写Advice代码,再定义切入点, 并启用AOP机制,Spring IoC容器自动创建Advice对象,切入的目标对象,再检查切入点语法,自动将Advice代码切入到指定的连接点执行。

  5. 目标对象(Target)
    目标对象就是切面要切入的类以及他的方法。
    将原始包含切面重复代码和不重复代码分离后, 重复代码成为Advice,剩余的不重复代码变成目标对象。
    Spring AOP通过整合切面和目标对象,还原成原始的代码状态。

  6. 代理类(AOP proxy)
    Spring实现AOP,是通过创建一个代理对象,将Advice对象 和目标对象 结合在一起,
    执行代理对象的方法,完成切面代码和目标代码的共同执行。

  7. 织入(Weaving)
    织入是指Spring框架将切面和目标对象,按照切入点的要求,组装成代理对象的过程。
    Spring AOP是动态织入的,即在运行时自动完成。

Spring支持的Advice类型

根据Spring支持的方法调用的连接点位置,Spring AOP支持如下5种类型的Advice。

  1. 方法前Advice(Before advice)
    在目标对象的方法调用前切入的切面。

  2. 方法返回后Advice(After returning advice)
    当目标对象的方法正常执行,没有异常,并返回后,切入。

  3. 方法后Advice(After (finally) advice)
    当目标对象方法执行结束后切入。即使方法因为抛出异常,没有正常返回,也切入。
    这一点是与方法返回后Advice不一样。

  4. 环绕Advice(Around advice)
    环绕是在Advice代码分成2部分,一部分代码在目标对象的方法调用前切入,另一部分代码在目标对象的方法调用后切入。
    像业务层案例中的Hibernate API编程就是环绕Advice,在session.save方法前,切入的切面代码完成SessionFactory获取,Session的open,事务的启动,在执行session.save方法后,切入的代码完成事务的提交, session的关闭。

  5. 方法抛出异常后Advice(After throwing advice)
    此切面是在目标对象的方法调用期间出现了异常,我们可以定义要切入的异常类型,当异常类型与定义的异常类型相同时,切面的Advice代码自动启动运行。

Spring AOP 注解类实现方式

Spring AOP模块实现AOP编程是通过集成了著名的AOP框架AspectJ实现的。
目前支持其第5版,即AspectJ 5.
Spring AOP编程的核心是:

  1. 使用AspectJ的注解类实现Advice类和方法的编程。
  2. 使用AspectJ的注解类实现切入点的定义和方法的编程。
  3. Spring IoC容器自动扫描这些注解类修饰的类和方法,自动创建切面类对象,目标对象,代理对象,并执行代理对象的方法,实现切面与目标对象的合成。

依赖库的引入
要在Spring项目中使用AspectJ,需要因为如下依赖类库:

  1. 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>
  1. 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编程的过程

  1. 定义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的方法调用。

  2. 定义Advice切面方法。
    在Advice类中定义切面方法,如下定义一个方法前的切面代码,只在执行指定目标对象的方法前输出一个字符串,并没有实际意义,但可以演示Advice的使用。

    @Component
    @Aspect
    public class ServiceLayAdvice {//切面方法
    public void methodBeforeRun() throws Exception{System.out.println("业务层方法前切面代码执行。。。。");}}
    
  3. 在方法前使用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在方法调用前执行。

  4. 测试
    在测试类中调用部门业务层对象的任意方法,这里测试的是取得指定部门的查询方法,AOP的Advice会自动在方法前切入运行。

Spring AOP使用AspectJ提供的切面注解类

  1. @Pointcut
    切入点的定义。该注解类修改的方法就是一个切入点,可以被其他切面Advice类引用。

  2. @Before
    声明方法前Advice切面方法。属性value指定切入点,默认属性,可以省略。

  3. @After
    方法结束后切面,当方法正常返回或抛出异常返回都切入。

  4. @AfterRetruning
    方法返回后切面,只有当方法正常返回后,且没有抛出异常才切入。

  5. @Around
    方法环绕切面,在目标对象方法的执行前切入方法前代码, 方法接收后再切入方法后代码。
    环绕切面通常可用于计算方法的执行时间,以及事务处理等。

  6. @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中,还是推荐单独编写切入点类和切入点方法。

切入点类和切入点方法的定义语法

  1. 切入点类前要使用@Component (让Spring IoC容器能扫描到), @Aspect 进行注释(让Spring IoC容器解析为一个切面类)。
  2. 在类中定义切面方法,并使用@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切入点语言支持如下常用的表达式:

  1. 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,..))")
  1. within
    限定指定类型的bean的所有方法。
    使用案例:
    within(com.city.oa.service…) 包com.city.oa.service包及子包下所有类的方法
    实际应用
    @Pointcut("within(com.city.oa.service…
    )")

  2. this
    指定Bean类型的所有方法,如果指定最好指定为接口类型,不要指定到实现类。
    this(com.city.oa.service.IDepartmentService)
    使用:
    @Pointcut(“this(com.city.oa.service.IDepartmentService)”)

  3. target
    与this类型,指定固定类型的Bean的所有方法
    target(com.city.oa.service.IDepartmentService)
    使用:
    @Pointcut(“target(com.city.oa.service.IDepartmentService)”)

  4. args
    指定参数类型的Bean的方法。Spring会在IoC容器中查找所有args指定参数的类的方法。实际使用很少。
    args(java.io.Serializable)
    args(java.lang.String)
    args(int)
    使用:
    @Pointcut(“args(java.lang.String)”)

  5. @target
    指定Bean的类前有指定注解类的Bean的所有方法
    @target(org.springframework.transaction.annotation.Transactional) 所有使用@Transactional修饰的Bean类。
    @target(org.springframework.stereotype.Service) 所有使用@Service修饰的类的所有方法。

  6. @args
    指定方法中参数前有注解类修饰的方法。
    @args(corg.springframework.beans.factory.annotation.Qualifier) 指定参数前有@Qualifier修饰的参数的所有方法。

  7. @within
    与@target类型,指定有注解类的Bean类的所有方法
    @within(org.springframework.transaction.annotation.Transactional)

  8. @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 事务编程

  1. 声明式事务编程(declarative transaction management)
    通过配置方式实现事务处理,不需要编写事务处理代码。
    Spring内置了事务Advice,不需要编写事务处理代码。
    通过设置事务Advice的切入点,并启用Spring事务管理机制,Spring自动将事务应用到目标类的方法。并且新版的Spring通过注解类@Transactional就可以配置事务的切入点,Spring 事务Advice自动切入使用@Transactional注解类注解的类的方法,或直接注解的方法,极大简化了事务的配置。

    实现方式:

    1. Spring Java Config配置类 + @Transactional注解类
      在Spring Boot流行的情况,使用Java配置类配置Spring IoC管理的Bean对象已经变得非常流行。
    2. Spring XML配置文件+@Transactional注解类
      XML方式配置Spring在公司项目开发中还普遍使用。
      虽然新项目的开发已经初步向配置类方向方法,还是有非常多的Spring项目依然使用XML文件配置。
    3. 纯的XML配置方式
      此种方式在新的项目中使用越来越少。
  2. 编程式事务处理(programmatic transaction management)
    Spring也支持统一的编程式事务处理,不再需要各自框架自己的事务管理API编程,实现了事务编程的统一模式。
    Spring提供了事务编程模块API:TransactionTemplate

Spring 事务处理API

  1. PlatformTransactionManager:通用的事务管理器接口
    Spring提供了所有资源事务处理标准的事务处理管理器的接口。
    该接口定义了所有类型的资源事务管理器必须提供的功能。
    Spring提供了各种资源管理的事务管理器实现类,如Hibernate,JPA,JDO,JDBC,JMS,JTA等,都实现PlatformTransactionManager接口。

    1. JDBC的事务接口实现类:
      org.springframework.jdbc.datasource.DataSourceTransactionManager
      使用在JDBC实现数据库的编程环境下。
      MyBaits持久层框架也是使用JDBC模式,也使用此事务管理器实现类,Spring没有提供MyBatis专门的事务管理器。

    2. Hibernate的事务接口实现类
      org.springframework.orm.hibernate5.HibernateTransactionManager
      Hibernate框架使用自己的事务管理API,Spring提供了支持Hibernate5的事务管理实现类。

    3. JPA的事务接口实现类
      JpaTransactionManager

    4. JMS事务接口实现类

      JmsTransactionManager

    5. JTA事务实现类
      JtaTransactionManager

  2. TransactionDefinition
    事务的定义接口,可以实现各种类型事务的统一属性定义。
    通过此接口可以设置不同资源的事务的特性,如事务的隔离级别,传播特性,只读,超时等。

  3. TransactionStatus
    统一的事务控制接口,定义了各种事务的控制方法。
    实现各种资源管理事务的统一控制,如使用TransactionStatus.commit() 可以提交事务,不管使用的是Hibernate,MyBatis,还是JDBC,JTA等等。

什么是脏读、幻读、不可重复读?

脏读 : 一个事务读取到另一事务未提交的更新数据
不可重复读 : 在同一事务中, 多次读取同一数据返回的结果有所不同, 换句话说, 后续读取可以读到另一事务已提交的更新数据. 相反, "可重复读"在同一事务中多次读取数据时, 能够保证所读数据一样, 也就是后续读取不能读到另一事务已提交的更新数据
幻读 : 一个事务读到另一个事务已提交的insert数据

Spring--事务处理编程相关推荐

  1. Spring切面编程

    Spring切面编程 1.导入maven依赖 2.切面实现 2.1.切面@Aspect 2.2.切点@PointCut 2.2.1.execution表达式语法 2.3.切面增强处理Advice声明 ...

  2. Spring事务处理流程和原理(动脑学院笔记)

    一.事务理论 1.事务的特性  2.事务的隔离级别 3.事务的传播   4.利用数据库事务实现应用事务控制 要求:同一个事务需要同一个库的同一个连接.  5.单一数据源,如何让事务的所有操作使用同一连 ...

  3. java元婴期(20)----java进阶(spring(4)---spring aop编程(全自动)AspectJ)

    spring aop编程:全自动[掌握] 从spring容器获得目标类,如果配置aop,spring将自动生成代理. 要确定目标类,aspectj 切入点表达式,导入jar包(maven项目直接导入相 ...

  4. Spring注解编程基石(一)

    目录 Java注解 Java原生注解 元注解 Stereotype 注解 组合注解 组合注解实现的基础 @AliasFor 隐式别名 @AliasFor 和 @Inherited 区别 注解解析工具 ...

  5. Spring注解编程基石(二)

    目录 辅助类 AttributeMethods AnnotationFilter RepeatableContainers MergedAnnotation接口 AnnotationsProcesso ...

  6. Spring注解编程基石(三)

    目录 AnnotationUtils 源码分析 方法列表 方法源码 AnnotatedElementUtils 源码分析 Spring注解编程基石(一) Spring注解编程基石(二) Spring注 ...

  7. Spring注解编程基石(四)

    目录 AnnotationsScanner 扫描方法 扫描source为Class方法 扫描source为Method方法 辅助方法 MergedAnnotationSelector MergedAn ...

  8. Spring事务处理之 编程式事务 和 声明式事务

    对事务概念还不了解的可以先看一下 MySQL事务管理(初步了解) 这篇文章 !!! Spring事务管理学习步骤: 1.掌握Spring事务属性 2.掌握Spring事务核心API 3.掌握Sprin ...

  9. 设计模式——Spring注解编程模型

    文章目录 1. 引言 2. Spring注解编程模型 2.1 元注解(Meta-Annotations) 2.2 Spring模式注解(Stereotype Annotations) 2.3 Spri ...

  10. Spring核心编程思想

    第01章:Spring Framework总览 (12讲)       01.课程介绍.mp4       02.内容综述.mp4       03.课前准备:学习三件套(工具.代码与大脑).mp4 ...

最新文章

  1. python fun
  2. 安全观之我见(三):省银之道在预防
  3. Oracle 表空间的段管理
  4. 一文搞定Linux shell脚本编程( 史上最全汇总 )
  5. Kudu 使用注意点
  6. 使用SoapUI生成wsdl文件客户端(二)
  7. c语言void nzp,二级C语言考试辅导教程第五章:函数[5]
  8. HDU 1016 Prime Ring Problem
  9. spring 中beanFactory和ApplicationContext的区别
  10. 龙果学院Elasticsearch顶尖高手系列-高手进阶篇完整版
  11. powerDesign逆向工程Mysql转Oracle
  12. jxt - 强结构文档数据表示协议
  13. python 中sample是什么_python中的sample什么意思
  14. 计算机屏幕的显示分辨率与什么有关,事实:显示器屏幕尺寸和分辨率之间是什么关系?...
  15. oracle mod函数
  16. 《Adobe Photoshop CS5中文版经典教程(全彩版)》—第2课2.6节替换图像中的颜色...
  17. 用PS做淘宝宝贝详情页及如何切图导出
  18. Laravel实现软删除
  19. Adobe 及 Acrobat Reader 下载链接(FTP)
  20. MySQL事务——事务隔离界别,MVCC

热门文章

  1. Amanda之安装、部署、测试以及优缺点
  2. 转载:NPOI导出到Excel表格
  3. ospf v3 及WIN XP ipv6
  4. OpenCV与AIPCV库——学习笔记(一)
  5. 问题五十四:怎么用ray tracing画参数方程表示的曲面(2)—— bezier surface
  6. 左边工具栏 隐藏_203 【Ps基础】 工具栏
  7. Python实现对nginx日志access.log统计
  8. 统计某一范围内所有的是K的倍数或者含有K的整数
  9. Matlab实现Faster-RCNN目标检测
  10. mysql+索引+rebuild_(solr系列:五) solr定时实时重建索引和增量更新