SpringAOP和Spring事物管理

Spring AOP :

Pointcut表达式:  designators-指示器  wildcards-通配符  operators-操作符

wildcards:  * -- 匹配任意数量的字符

+ -- 匹配制定类及其子类

..-- 一般用于匹配任意数的子包或参数

operator: && || !

Wildcards(通配符)

* 匹配任意数量的字符

+ 匹配指定类及其子类

.. 一般用于匹配任意数的子包或参数

Pointcut :切面表达式

designators:指示器,描述通过什么方式去匹配Java的那些方法

execution():匹配方法

匹配注解

@target()

@args()

@within()

@annotation()

within():匹配包/类型

this()/bean()/target():匹配对象

args():匹配参数

wildcards:通配符(*:匹配任意数量的字符;+匹配指定类及其子类;..:一般用于匹配任意数的子包或参数)

operators: 运算符(&&:与操作符;||或;!:非)

匹配包/类型 :

// 匹配ProductService类里头的所有方法

@Pointcut("within(com.imooc.service.ProductService)")

public void matchType() {

}

// 匹配com.imooc包及子包下所有类的方法

@Pointcut("within(com.imooc..*)")

public void matchPackage(){}

匹配对象:

1:this(包名):匹配AOP对象的目标对象指定类型的方法;

2:target(包名):匹配实现接口的目标对象的方法(不是AOP代理后的对象);

3:bean(包名):匹配所有以Service结尾的bean里头的方法;

/**

public class DemoDao implements IDao{}

*/

// 匹配AOP对象的目标对象为指定类型的方法,即DemoDao的aop代理对象的方法

@Pointcut("this(com.imooc.DemoDao)")

public void thisDemo() {}

// 匹配实现IDao接口的目标对象(而不是aop代理后的对象)的方法,这里即DemoDao的方法

@Pointcut("target(com.iommc.IDao)")

public void targetDemo() {}

// 匹配所有以Service结尾的bean里头的方法

@Pointcut("bean(*Service)")

public void beanDemo() {}

匹配参数

// 匹配任何以find开头而且只有一个Long参数的方法

@Pointcut("execution(* * ..find*(Long))")

public void argsDemo1() {}

// 匹配任何只有一个Long参数的方法

@Pointcut("args(Long)")

public void argsDemo2() {}

// 匹配任何find开头的而且第一个参数为Long型的方法

@Pointcut("execution(* *..find*(Long,..)")

public void argsDemo3() {}

// 匹配第一个参数为Long型的方法

@Pointcut("args(Long,..)")

public void argsDemo4() {}

匹配注解:

1:匹配方法级别的;

2:匹配类级别的;

3:匹配参数级别的;

@annotion:匹配方法级别的注解方法;

@within:匹配标注有Beta的类底下的方法;

@target:匹配标注有Repository的类底下的方法;

@args:匹配传入的参数类标注有Repository注解的方法;

示例 :

1: // 匹配方法标注有AdminOnly的注解的方法

@Pointcut("@annotation(com.imooc.demo.security.AdminOnly)")

public void annoDemo(){}

2: // 匹配标注有Beta的类地下的方法,要求的anntation的RetentionPolity级别的CLASS

@Pointcut("@within(com.google.common.annotations.Beta)")

public void annoWithDemo(){}

3: // 匹配标注有Repository的类地下的方法,要求的annotation的RetentionPolicy级别为RUNTIME

@Pointcut("@target(org.springframework.stereotype.Repository)")

public void annoTargetDemo() {}

4: //匹配传入的参数类标注有Repository注解的方法;

@Pointcut("@args(org.springframework.stereotype.Repository)")

public void annoArgsDemo(){}

@Before,表示在切点之前执行的插入的逻辑;

@Aspect切面类,标注界面类;

@Component,标注在类上,表示这个类交给spring托管;

execution表达式:

拦截方法:

@Pointcut("execution(public * com.imooc.service.*.*(..))");

拦截抛出的异常:

@Pointcut("exection(public * com.imooc.service.*.*(..) throws java.lang.IllegalAccessException)");

//匹配任何公共方法

@Pointcut("execution(public * com.imooc.service.*.*(..))")

//匹配com.imooc包及子包下Service类中无参方法

@Pointcut("execution(* com.imooc..*Service.*())")

//匹配com.imooc包及子包下Service类中的任何只有一个参数的方法

@Pointcut("execution(* com.imooc..*Service.*(*))")

//匹配com.imooc包及子包下任何类的任何方法

@Pointcut("execution(* com.imooc..*.*(..))")

//匹配com.imooc包及子包下返回值为String的任何方法

@Pointcut("execution(String com.imooc..*.*(..))")

//匹配异常

execution(public * com.imooc.service.*.*(..) throws java.lang.IllegalAccessException)

5种Advice:

1:@Before,前置通知;

2:@After(finally),后置通知,方法执行完成之后;

3:@AfterReturning,返回通知,成功执行之后执行;

4:@AfterThrowing,异常通知,抛出异常之后执行

5: @Around : 环绕通知

原理概述 : 织入的时机

1: 编译期(Aspectj)

2: 类加载时(Aspectj 5+)

3: 运行时(Spring AOP)

运行时织入:

1:静态代理与动态代理;

2:基于接口代理与基于继承代理;

代理模式;

组成:调用者,统一的接口、真实对象、代理者;

原理:通过接口,实现这样一个过程,在调用真实对象的时候,调用者并不直接与真实对象打交道,而是通过一个代理者与真实对象通信,代理者能够负责真实

对象的非业务逻辑,如日志管理、访问控制 、异常处理等,使得真实对象专注于业务逻辑的实现,不受非业务逻辑的干扰。

代理对象会把正真的业务逻辑委托给实际对象 而代理对象只会进行一写边缘的附加操作  这就是aop的实现原理.

代理对象调用目标对象的方法产生的异常需要抛出去,不能处理,因为代理对象的作用是对目标对象进行增强,不会对目标对象进行改变.

静态代理就是一个代理类根据被代理类的情况,被代理类有几个方法,代理类就需要有几个方法,每个方法都要对被代理类进行代理,这样会出现代码重复的情况,

如多个被代理方法其实前后需要执行的逻辑是一样的,但是静态代理还是需要为每个方法写一个代理方法,造成代码重复。动态代理根据放射得到被代理类执行的方

法和参数,避免了代码的重复。

静态代理的代码,静态代理的弊端:代理的对象越多.

JDK实现要点:

1类:java.lang.reflect.Proxy;

2接口:InvoctionHandler;

3只能基于接口进行动态代理.

动态代理实现时,需要的接口,InvocationHandler接口。

注意:在捕获异常之后,执行插入程序,然后还需要将异常在catch代码块内抛出去!

jdk运行期动态代理源码解析:其实就是真实类实现一个接口,我们再写一个类似于切面的类,实现invocationhandler接口且实现invoke方法,同时要保存真实类对象,

初始化时赋值对象,invoke方法中反射方式调用真是对象方法,在方法前后可以加上定制的逻辑,这个方法其实是动态代理对象调用的,动态代理对象是客户端通过动

态代理类实例化的,而动态代理类是真实对象方法执行前的运行期生成的.class类,这个类实现了和真实对象一样的接口,所以也有真实对象的方法,调用代理对象方

法时也就可以传入参数,然后代理对象再将方法和参数传递给invocationhandler的实例对象。

通过System.setProperties()可以设置保存jdk动态代理生成的字节码文件.

JDK与Cglib代理对比:

1:JDK只能针对有接口的类的接口方法进行动态代理;

2:Cglib基于继承来实现代理,无法对static、final类进行代理;

3:Cglib基于继承来实现代理,无法对private、static方法进行代理。

Cglib实现:

1:生成指定类对象的子类,也就是重写类中的业务函数。

2:执行回调函数,加入intercept()函数。

3:创建这个类的子类对象。

-----------------------------------------

反射技术实现;

methodProxy.invokeSuper();

JDK通过接口代理,所以只能代理实现接口的类的方法,而cglib通过继承实现代理,所以不能代理final类,也无法代理private和static方法.

无法对final类进行代理,因为final类不能被继承

关于Cglib无法对static类和方法进行代理:

单一的类是没有static修饰符的,只有静态类内部可以用static修饰;

对于static方法,它是属于类的,子类在不重写的情况下,是可以调用的,但是一旦重写了就无法调用了,普通的public方法可以通过super.method()调用,但是

static方法不行.

Spring如何创建代理bean?

JDK动态代理与Cglib代理是如何选用的?

-----------------------------

1:如果目标对象实现了接口,则默认采用JDK动态代理;

2:如果目标对象没有实现接口,则采用Cglib进行动态代理;

3:如果目标对象实现了接口,且强制Cglib代理,则使用Cglib代理;

继承JPARepository对数据操作实现自己的事务控制,@transactional会在子事务外层加一层事务控制,对事务整体进行控制,在方法执行前后判断事务需要进行回滚操作。

SpringBoot对缓存的一个控制:

1、引入依赖:

<dependency>

<groupId>org.springframework.boot</groupId>

<artifactId>spring-boot-starter-cache</artifactId>

</dependency>

2、使用注解:

@Cacheable(cacheNames={"menu"})

public List<String> getMenuList(){

  System.out.println("看看是不是只有第一次被调用");

  return Arrays.asList("java","C++","PHP");

}

使用SpringAop的注意事项/坑

1: 不宜把重要的业务逻辑放到aop中处理;

2: 无法拦截static,final方法,private方法;

3: 无法拦截内部方法调用.

实现AOP的方法被方法内部调用时是不会走AOP的织入逻辑的,因为内部调用AOP方法的调用对象是this,而this不是增强的代理对象,所以不会走织入代码,解决方法

就是用ApplicationContent获取到增强的代理对象的bean,然后用这个bean来执行AOP方法,就可以走织入的代码逻辑了.

Spring Aop 的坑,无法拦截方法内部调用,因为内部调用是this调用的,而不是代理类调用的.

无法拦截内部调用的原因:aop通过代理实现的,而省略的this是指该对象,而不是代理后的对象

解决aop无法内部调用的问题:通过spring的ApplicationContext获取该类的对象,就是代理对象,使用代理对象去调用内部方法.

解决方法:通过ApplicationContext来获取代理bean,通过代理bean调用方法。

课程总结:

1.面向切面编程是对面向对象编程的补充,主要用于日志记录,权限验证,事务配置等功能。

2.使用aspectJ实现aop,aspectJ是一个面向切面的框架,它扩展了Java语言。

3.主要注解:

@Aspect 标注说明Java类是切面配置的类 由@Pointcut和@Advice组成

@Pointcut 描述在哪些类的哪些方法植入代码 

@Advice表达在Pointcut表达式的什么时间执行

4. pointcut中的通配符,运算符,指示器(通过什么方式匹配植入的方法)

通配符:* 匹配任意数量的字符  +匹配指定类及其子类  ..一般用于匹配任意数的子包或参数

运算符:&&与操作符  || 或操作符  !非操作符

指示器:

a. @within 匹配包/类型

@Pointcut("within(com.imooc.service.ProductService")) //匹配ProductService类里的所有方法

@Pointcut("within(com.imooc..*)") //匹配com.imooc包及子包下所有类的方法

b. execution  表达式:方法的修饰符 返回值 包名.类名.方法(参数)

@Pointcut("execution(public * com.imooc.service.*Service.*(..))")//表示com.imooc.service包下以Service字符结尾的类中任意参数的所有方法

5.Advice 注明要在哪个切点执行什么操作,有几种方式

@Before("")  //意思是在切点执行前执行

@After("")  //意思是在切点执行前执行

@Around("") //表明在切点方法的前后都要执行该处理器方法

Spring事务 :

Spring事务管理接口:

PlatformTransactionManager:事务管理器

TransactionDefinition:事务定义信息(事务隔离级别、传播行为)(隔离、传播、超时、只读)

TransactionStatus:事务具体运行状态

事务管理器PlatformTransactionManager

Spring为不同的持久化框架提供了不同PlatformTransactionManager接口实现;

org.springframework.jdbc.datasource.DataSourceTransactionManager : 使用Spring JDBC或iBatis进行持久化数据时使用.

org.springframework.orm.hibernate3.HibernateTransactionManager : 使用Hibernate3.0版本进行持久化数据时使用.

org.springframework.orm.jpa.JpaTransactionManager : 使用JPA进行持久化时使用

org.springframework.jdo.JdoTransactionManager : 当持久化机制是Jdo时使用

org.springframework.transaction.jta.JtaTransactionManager : 使用一个JTA实现管理事务,在一个事务跨越多个资源时必须使用.

TransactionDefinition定义事务隔离级别

如果不考虑隔离性,会引发如下的安全问题:

1.脏读。

一个事务读取了另一个事务改写但还未提交的数据,如果这些数据被回滚,则读到的数据是无效的。

2.不可重复读。

在同一个事务中,多次读取同一数据返回的结果有所不同。

3.幻读。

一个事务读取了几行记录后,另一个事务插入一些记录,幻读就发生了。再后来的查询中,第一个事务就会发现有些原来没有的记录。

隔离级别的出现就是为了解决以上问题的。

数据库提供的事务的隔离级别(四种):

1.READ_UNCOMMITED;

允许你读取还未提交的改变了的数据,可能导致脏,幻,不可重复读。

2.READ_COMMINTED:

允许在并发事务已经提交后读取,可防止脏读,但幻读和不可重复读还是有可能发生。

3.REPEATABLE_READ:

对相同字段的多次读取是一致的,除非数据被事务本身改变,可防止脏读,不可重复读,但幻读仍有可能出现。

4.SERILIZABLE:

完全服从ACID的隔离级别,确保不发生脏读,幻读,不可重复读,这在所有的隔离级别中是最慢的,它是典型的完全通过锁定在事务中涉及的数据表来完成的。

除了以上的数据库提供的事务隔离级别,spring提供了Default隔离级别,该级别表示spring使用后端数据库默认的隔离级别。

MySQL默认事务隔离级别:REPATABLE_READ(可能出现幻读)

Oracle默认:READ_COMMITTED(可能出现不可重复读和幻读)

propagation_required:a存在事务,则b与a同一事务,如果a没有事务,则b新起事务

propagation_supported:a存在事务,则b与a同事务,如果a没有事务,则b也没有事务

propagation_mondatary:a存在事务,则b与a同事务,如果a没有事务,则抛异常

propagation_required_new:如果a存在事务,b新起事务

propagation_not_supported:如果a存在事务,b不已事务运行

propagation_never:如果出现事务,直接抛出异常

propagation_nested:a事务运行结束后,会有保存点,这边可以自定事务,b出错,a可以回滚或者就到a的保存点

TransactionDefinition定义事务之事务的传播行为(002)<br>

<br>

事务的传播行为有七种,这七种行为可以分为三类,图中前三个分为一类(让aaa()和bbb()操作在同一事务里),中间三个为一类(保证aaa()和bbb()操作在不同一事务里),最后为一类(aaa()执行完成后,设置一个保存点,如果bbb()发生异常,将回滚到保存点或初始状态)。<br>

<br>

重点记住PROPAGATION_REQUIRED, PROPAGATION_REQUIRES_NEW, PROPAGATION_NESTED

相关代码(公共1):

//package cn.muke.spring.demo1;

@AccountDao.java

/**

* 转账案例的DAO层的接口

*/

public interface AccountDao {

/**

* out :转出账号

* money:转出金额

*/

public void outMoney(String out,Double money);

/**

* in :转入账号

* money:转入金额

*/

public void inMoney(String in,Double money);

}

@AccountService.java

/**

* 转账案例的业务层接口

*/

public interface AccountService {

/**

* out :转出账号

* in :转入账号

* money:转账金额

*/

public void transfer(String out,String in,Double money);

}

@AccountDaoImpl.java

/**

* 转账案例的DAO层的实现类

*/

public class AccountDaoImpl extends JdbcDaoSupport implements AccountDao {

/**

*  out :转出账号

*  money:转出金额

*/

public void outMoney(String out, Double money) {

String sql="update account set money=money-? where name=?";

this.getJdbcTemplate().update(sql,money,out);

}

/**

*  in :转入账号

*  money:转入金额

*/

public void inMoney(String in, Double money) {

String sql="update account set money=money+? where name=?";

this.getJdbcTemplate().update(sql,money,in);

}

}

事务的传播行为和隔离级别[transaction behavior and isolated level]

Spring中事务的定义:

一、Propagation :

  key属性确定代理应该给哪个方法增加事务行为。这样的属性最重要的部份是传播行为。有以下选项可供使用:

PROPAGATION_REQUIRED--支持当前事务,如果当前没有事务,就新建一个事务。这是最常见的选择。

PROPAGATION_SUPPORTS--支持当前事务,如果当前没有事务,就以非事务方式执行。

PROPAGATION_MANDATORY--支持当前事务,如果当前没有事务,就抛出异常。

PROPAGATION_REQUIRES_NEW--新建事务,如果当前存在事务,把当前事务挂起。

PROPAGATION_NOT_SUPPORTED--以非事务方式执行操作,如果当前存在事务,就把当前事务挂起。

PROPAGATION_NEVER--以非事务方式执行,如果当前存在事务,则抛出异常。

很多人看到事务的传播行为属性都不甚了解,我昨晚看了j2ee without ejb的时候,看到这里也不了解,甚至重新翻起数据库系统的教材书,但是也没有找到对这个的分析。今天搜索,找到一篇极好的分析文章,虽然这篇文章是重点分析PROPAGATION_REQUIRED 和 PROPAGATION_REQUIRED_NESTED的

解惑 spring 嵌套事务

********TransactionDefinition 接口定义*******************

    int PROPAGATION_REQUIRED = 0; 



    int PROPAGATION_SUPPORTS = 1; 

    int PROPAGATION_MANDATORY = 2; 


    int PROPAGATION_REQUIRES_NEW = 3; 



    int PROPAGATION_NOT_SUPPORTED = 4; 


    int PROPAGATION_NEVER = 5; 


    int PROPAGATION_NESTED = 6; 

*************************************************************************

在这篇文章里,他用两个嵌套的例子辅助分析,我这里直接引用了。

********************sample***********************

ServiceA { 



void methodA() { 

ServiceB.methodB(); 



ServiceB { 


void methodB() { 


}     

*************************************************

我们这里一个个分析吧

1: PROPAGATION_REQUIRED

加入当前正要执行的事务不在另外一个事务里,那么就起一个新的事务

比如说,ServiceB.methodB的事务级别定义为PROPAGATION_REQUIRED, 那么由于执行ServiceA.methodA的时候,

ServiceA.methodA已经起了事务,这时调用ServiceB.methodB,ServiceB.methodB看到自己已经运行在ServiceA.methodA

的事务内部,就不再起新的事务。而假如ServiceA.methodA运行的时候发现自己没有在事务中,他就会为自己分配一个事务。

这样,在ServiceA.methodA或者在ServiceB.methodB内的任何地方出现异常,事务都会被回滚。即使ServiceB.methodB的事务已经被

提交,但是ServiceA.methodA在接下来fail要回滚,ServiceB.methodB也要回滚

2:  PROPAGATION_SUPPORTS

如果当前在事务中,即以事务的形式运行,如果当前不再一个事务中,那么就以非事务的形式运行

这就跟平常用的普通非事务的代码只有一点点区别了。不理这个,因为我也没有觉得有什么区别

3:  PROPAGATION_MANDATORY

必须在一个事务中运行。也就是说,他只能被一个父事务调用。否则,他就要抛出异常。

4:  PROPAGATION_REQUIRES_NEW

这个就比较绕口了。 比如我们设计ServiceA.methodA的事务级别为PROPAGATION_REQUIRED,ServiceB.methodB的事务级别为PROPAGATION_REQUIRES_NEW,

那么当执行到ServiceB.methodB的时候,ServiceA.methodA所在的事务就会挂起,ServiceB.methodB会起一个新的事务,等待ServiceB.methodB的事务完成以后,

他才继续执行。他与PROPAGATION_REQUIRED 的事务区别在于事务的回滚程度了。因为ServiceB.methodB是新起一个事务,那么就是存在

两个不同的事务。如果ServiceB.methodB已经提交,那么ServiceA.methodA失败回滚,ServiceB.methodB是不会回滚的。如果ServiceB.methodB失败回滚,

如果他抛出的异常被ServiceA.methodA捕获,ServiceA.methodA事务仍然可能提交。

5:  PROPAGATION_NOT_SUPPORTED

当前不支持事务。比如ServiceA.methodA的事务级别是PROPAGATION_REQUIRED ,而ServiceB.methodB的事务级别是PROPAGATION_NOT_SUPPORTED ,

那么当执行到ServiceB.methodB时,ServiceA.methodA的事务挂起,而他以非事务的状态运行完,再继续ServiceA.methodA的事务。

6:  PROPAGATION_NEVER

不能在事务中运行。假设ServiceA.methodA的事务级别是PROPAGATION_REQUIRED, 而ServiceB.methodB的事务级别是PROPAGATION_NEVER ,

那么ServiceB.methodB就要抛出异常了。

7:  PROPAGATION_NESTED

理解Nested的关键是savepoint。他与PROPAGATION_REQUIRES_NEW的区别是,PROPAGATION_REQUIRES_NEW另起一个事务,将会与他的父事务相互独立,

而Nested的事务和他的父事务是相依的,他的提交是要等和他的父事务一块提交的。也就是说,如果父事务最后回滚,他也要回滚的。

而Nested事务的好处是他有一个savepoint。

*****************************************

ServiceA { 



void methodA() { 

try {

  //savepoint 

ServiceB.methodB();    //PROPAGATION_NESTED 级别

} catch (SomeException) { 

// 执行其他业务, 如 ServiceC.methodC(); 


********************************************

也就是说ServiceB.methodB失败回滚,那么ServiceA.methodA也会回滚到savepoint点上,ServiceA.methodA可以选择另外一个分支,比如

ServiceC.methodC,继续执行,来尝试完成自己的事务。

但是这个事务并没有在EJB标准中定义。

二、Isolation Level(事务隔离等级):

1、Serializable:最严格的级别,事务串行执行,资源消耗最大;

2、REPEATABLE READ:保证了一个事务不会修改已经由另一个事务读取但未提交(回滚)的数据。避免了“脏读取”和“不可重复读取”的情况,但是带来了更多的性能损失。

3、READ COMMITTED:大多数主流数据库的默认事务等级,保证了一个事务不会读到另一个并行事务已修改但未提交的数据,避免了“脏读取”。该级别适用于大多数系统。

4、Read Uncommitted:保证了读取过程中不会读取到非法数据。

隔离级别在于处理多事务的并发问题。

我们知道并行可以提高数据库的吞吐量和效率,但是并不是所有的并发事务都可以并发运行,这需要查看数据库教材的可串行化条件判断了。

这里就不阐述。

我们首先说并发中可能发生的3中不讨人喜欢的事情

1:  Dirty reads--读脏数据。也就是说,比如事务A的未提交(还依然缓存)的数据被事务B读走,如果事务A失败回滚,会导致事务B所读取的的数据是错误的。

2:  non-repeatable reads--数据不可重复读。比如事务A中两处读取数据-total-的值。在第一读的时候,total是100,然后事务B就把total的数据改成200,事务A再读一次,结果就发现,total竟然就变成200了,造成事务A数据混乱。

3:  phantom reads--幻象读数据,这个和non-repeatable reads相似,也是同一个事务中多次读不一致的问题。但是non-repeatable reads的不一致是因为他所要取的数据集被改变了(比如total的数据),但是phantom reads所要读的数据的不一致却不是他所要读的数据集改变,而是他的条件数据集改变。比如Select account.id where account.name="ppgogo*",第一次读去了6个符合条件的id,第二次读取的时候,由于事务b把一个帐号的名字由"dd"改成"ppgogo1",结果取出来了7个数据。

  Dirty reads          non-repeatable reads            phantom reads

Serializable                    不会                  不会                          不会

REPEATABLE READ          不会                  不会                            会

READ COMMITTED            不会                    会                            会

Read Uncommitted            会                    会                            会

三、readOnly

事务属性中的readOnly标志表示对应的事务应该被最优化为只读事务。这是一个最优化提示。在一些情况下,一些事务策略能够起到显著的最优化效果,例如在使用Object/Relational映射工具(如:Hibernate或TopLink)时避免dirty checking(试图“刷新”)。

四、Timeout

  在事务属性中还有定义“timeout”值的选项,指定事务超时为几秒。在JTA中,这将被简单地传递到J2EE服务器的事务协调程序,并据此得到相应的解释。

事务的API介绍

一、简介

PlatformTransactionManager - 平台事务管理器,真正用来管理事务的接口,包含事务的提交,回滚等信息

TransactionDefinition - 事务定义信息(隔离级别、传播行为、是否超时、设置只读)

TransactionStatus - 事务具体的运行状态(是否已经提交,是否有保存点,是不是一个新的事务等等这些状态)

关系:

首先会根据TransactionDefinition事务定义的信息(比如定义了什么样的隔离级别,定义什么样的传播行为),由PlatformTransactionManager对事务进行管理,进行事务管理的过程中,事务会产生一些相应的状态,这些状态在TransactionStatus中

二、PlatformTransactionManager 接口

1. DataSourceTransactionManager

使用Spring JDBC 或iBatis进行持久化数据时使用

2. HibernateTransactionManager

使用Hibernate3.0版本进行持久化数据时使用

三、TransactionDefinition

1.事务隔离级别

解决脏读、不可重复读、幻读等安全问题

事务隔离级别(四种):

DEFAULT

READ_UNCOMMITED

READ_COMMITED

REPEATABLE_READ

SERIALIZABLE

2.事务的传播行为

解决业务层的方法之间的相互调用的问题(在调用方法的过程中,事务是如何传递的)

事务的传播行为有七种,又分为三类:

第一类共同点:A和B方法在同一个事务中。

*PROPAGATION_REQUIRED

PROPAGATION_SUPPORTS

PROPAGATION_MANDATORY

第二类共同点:A 方法和 B 方法不在同一个事务里面。

*PROPAGATION_REQUIRES_NEW

PROPAGATION_NOT_SUPPORTED

PROPAGATION_NEVER

第三类:如果 A 方法有的事务执行完,设置一个保存点,如果 B 方法中事务执行失败,可以滚回保存点或初始状态。

*PROPAGATION_NESTED

四、TransactionStatus

TransactionStatus接口用来记录事务的状态

该接口定义了一组方法,用来获取或判断事务的相应状态信息.

平台事务管理器(PlatformTransactionManager)会根据TransactionDefinition中定义的事务信息(包括隔离级别、传播行为)来进行事务的管理,在管理的过程中事务可能

产生了保存点或事务是新的事务等情况,那么这些信息都会记录在TransactionStatus的对象中.

TransactionStatus记录事务的状态信息(刷新、是否有保存点、是否完成、是否是一个新事务、是否只回滚、设置只回滚)

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 200,392评论 5 470
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 84,258评论 2 377
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 147,417评论 0 332
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 53,992评论 1 272
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 62,930评论 5 360
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,199评论 1 277
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,652评论 3 390
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,327评论 0 254
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,463评论 1 294
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,382评论 2 317
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,432评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,118评论 3 315
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,704评论 3 303
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,787评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,999评论 1 255
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,476评论 2 346
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,057评论 2 341

推荐阅读更多精彩内容