Spring的事务控制

编程式事务控制

通过写代码的方式,去控制事务,有三个api

PlatformTransactionManager-spring的事务管理器,提供了常用的操作事务的方法
  • TransactionStatus
  • getTransaction(TransactionDefination defination)  获取事务的状态信息
void commit(TransactionStatus status)        提交事务void rollback(TransactionStatus status)      回滚事务

PlatformTransactionManager是接口类型,不同的Dao层技术则有不同的实现类,如jdbc或mybatis是和hibernate时的实现是不一样的

TransactionDefinition 事务的定义信息对象

内部封装事务的一些参数,方法如下:

  • int getIsolationLevel()       获得事务的隔离级别
  • int getPropogationBehavior()  获得事务的传播行为
  • int getTimeout()              获得超时时间
  • boolean isReadOnly()          是否只读
  1. 事务的隔离级别:
    设置隔离级别,可以解决事务并发产生的问题,如脏读、不可重复读和虚读(幻读)。
  • READ-UNCOMMITTED:读未提交,不能解决
  • READ-COMMITTED:能解决脏读
  • REPEATABLE_READ:可重复读,能解决不可重复读
  • SERIALIZABLE:串行化,全能解决,但性能低
  • DEFAULT:默认
事务的传播行为
传播行为的主要作用:解决业务方法在调用业务方法时,事务同一性的问题;即在开发时,业务层有很多方法,会出现A业务方法调用B业务方法,若对AB两个业务方法都进行事务控制,则A调用B时会出现重复或统一的问题。
  • REQUIRED(required):如果当前没有事务,就新建一个事务,如果已经存在一个事务,就加入到这个事务,是一般的选择(默认值);即当A业务方法调用B业务方法,B业务方法看A业务方法当前有没有事务,如果B业务方法看A业务方法没有事务,就新建一个事务,若A业务方法已经有事务,B业务方法就加入到这个事务
  • SUPPORTS(supports): A业务方法调用B业务方法,B看A有没有事务,若有事务,则支持当前事务,若当前没事务,就以非事务方式执行。
  • MANDATORY(mandatory):A业务方法调用B业务方法,若当前没有业务,就抛出异常
  • REQUIRED_NEW
  • NOT_SUPPORTED
  • NEVER
  • NESTED
  • 超时时间:超时限制
  • 是否只读
    事务定义信息对象,若使用注解方式,需要注解配置
TransactionStatus

TransactionStatus接口提供的是事务具体的运行状态

  • boolean hasSavePoint()        是否存储回滚点
  • boolean isCompleted()         事务是否完成
  • boolean isNewTransacction()   是否是新事务
  • boolean isRollbackOnly()      事务是否回滚
    这些状态信息不需要配置进行维护,状态随着事务的运行,是个被动信息,不是事务主动控制的。
    事务的状态对象和前两者的关系:
    平台事务管理器指定事务控制行为,事务的定义对象时维护事务的信息,事务运行状态是封装一些状态信息,是被动的。
    平台事务管理器+事务定义对象=事务状态对象

基于XML的声明式事务控制

什么是声明式事务控制

即用声明的方式来处理事务;声明,指在配置文件中声明,用在Spring配置文件中声明式的处理事务来代替代码式的处理事务

声明式事务处理的作用

  • 不侵入开发的组件,即解耦性;业务逻辑对象不会意识到处于事务管理之中,因为事务管理是属于系统层面的服务,而不是业务逻辑的一部分,即AOP思想--切点:事务 被增强的是业务方法 通知:事务增强
  • 在不需要事务管理的时候,只需要在设定文件上修改一下,即可移去事务管理服务,无需改变代码重新编译

Spring声明式事务控制底层就是AOP

业务背景

  • domain:保存Account表结构
  • dao:实现out函数和in函数接口和实现,实现控制money
  • service:实现转账服务,控制转入人和转出人和转账金额
  • web层controller:实现转账功能
    一般在业务层(service)进行事务控制,但当前存在问题:
    public void transfer(String outMan, String inMan, double money) {
        accountDao.out(outMan,money);
        accountDao.in(inMan,money);
    }

当前service对transfer方法进行事务控制,当调用out方法时,调用jdbc.Template的update方法,是一个事务,再执行in方法时,还是jdbc模板调用update方法,是另一个事务,此时不能进行事务控制
若此时两者间出现错误,则执行out函数后,出现错误没有执行in函数,则数据库数据错误。即此时业务层transfer函数并没有实现业务控制。
此时就可以把业务层的transfer函数当成一个切面进行AOP处理。

声明式事务控制的实现

声明式事务控制明确事项:

  • 谁是切点?    --转账方法
  • 谁是通知?    --事务增强(事务控制)
  • 谁是切面?
    快速入门
  1. xml配置文件中引用tx命名空间,操作和之前引入context的方法一样

  2. 确定目标对象,如service,内部的方法就是切点

  3. 配置事务通知

    配置文件设定:


  • 首先引用事务tx标签 然后设定advice id,和之前bean id性质一样,然后设置transaction-manager,设定事务管理器,如jdbc或mybatis使用的事务管理器(DataSourceTransactionManager)与hibernate时不一样,这个事务管理器可以自己设定
  • 设定好之后,内部需要注入DataSource至此平台事务管理器配置完成
  • 然后将配制好的平台事务管理器配置到事务增强里
  • 然后配置方法属性。
  • 然后配置事务的aop织入,其中aop专门为事务增强有配置,advisor;然后配置切点和切点表达式
  • 然后测试


```

tx:attributes-事务的属性,即编程式里TransactionDefination里的内容,里面设定事务的属性信息

tx:method-哪些方法被增强 isolation-管理级别 propagation-传播行为 time-out-失效时间 read-only-是否只读
attributes内可设置多个方法的配置

  • 号的使用:如method name设定成update*,即update开头的所有方法都进行配置
xml声明式事务控制的配置要点
  • 平台事务管理器配置
  • 事务通知的配置
  • 事务aop织入的配置

同时和aop一样,可以抽取point切点表达式


基于注解的声明式事务控制

一般情况下,自定义的bean用注解,非自定义的bean用xml配置
首先把Dao和Service用注解方式配置,具体操作见前-设置注解,设置组件自动扫描
然后替换掉事务增强信息和aop织入相关,找到需要对应事务控制的方法,可以通过@Transactional注解根据不同方法进行单独配置

    @Transactional(isolation = Isolation.READ_COMMITTED,propagation = Propagation.REQUIRED)
    public void transfer(String outMan, String inMan, double money) {
        //开启事务
        accountDao.out(outMan,money);
        accountDao.in(inMan,money);
        //提交事务
    }
    @Transactional(isolation = Isolation.DEFAULT)
    public void xxx(){

    }

还可以在类上进行定义,代表当前类上所有方法都使用此事务配置,若多个配置,就近原则,离函数近的地方起作用
如果配置了@Transactional,需要在xml文件中配置注解驱动


注解配置声明式事务控制解析
  1. 使用@Transactional在需要进行事务控制的类或方法上修饰,注释可用的属性同xml配置方式,例如隔离级别,传播行为等
  2. 注解使用在类上,那么该类下的所有方法都同一套注解参数配置
  3. 使用在方法上,不同的方法可以采用不同的事务参数配置
  4. Xml配置文件中需要进行配置注解驱动
注解声明式事务控制的配置要点
  • 平台事务管理器配置在xml中配置
  • 事务通知的配置使用@Transactional注解配置
  • 事务注解驱动的配置 tx:annotation-driven

ctrl+d复制这一行到下一行 ctrl+y删除当前行