Spring_对事务的支持

前文:Spring_基于Spring的JDBC

 

事务应该在哪一层?

前文中,我们知道Spring的JDBC会帮我们管理事务。

在这种情况下,会出现什么问题呢?

一些伪代码:

public class AccountDaoImpl implements IAccountDao{
    /* 转入 */
    public void transin(Long inId, BigDecimal value){
        // do work
    }
    /* 转出 */
    public void transout(Long outId, BigDecimal value){
        // do work
    }
}
public class AccountServiceImpl implements IAccountService{
    /* 转账方法 */
    public void transfer(Long inId, Long outId, BigDecimal value){
        accountDao.transout(outId, value); // 转出
        accountDao.transin(inId, value); // 转入
    }
}

可以看到,在Service层中,转账方法是通过调用DAO层的转出、转入方法实现的。

但是,由于事务是在DAO层中进行管理的,若Service层在转出后,系统出现异常,转入代码将无法继续正常执行。

 正确的JDBC转账流程

1、进入Service层的转账方法时:获取DataSoure对象,得到Connection对象。

2、关闭JDBC的事务自动提交:Connection对象.setAutoCommit(false);

3、将Connection对象绑定到当前线程中。

4、调用DAO层的方法,其Connection对象要从当前线程中获取。

5、正常执行则提交事务;出现异常则回滚。

 

Spring的事务管理 

· 相关接口

TransactionDefinition

封装事务的隔离级别,超时时间。是否为只读事务和事务的隔离级别,转播规则等事务属性。

可通过XML配置其具体信息。

PlatformTransactionManager

根据TeansactionDefinition提供的事务属性,创建事务。

TransactionStatus 

封装了事务的具体运行状态。

如是否新开事务,是否已提交事务,可设置当前事务为rollback-only等。

 · 事务管理的方式

Spring支持编程式事务管理和声明式事务管理。

编程式事务管理

如使用Hibernate,我们需要在代码中显式调用beginTransaction()、commit()、rollback()等事务管理相关的方法,这就是编程式事务管理。

通过 Spring 提供的事务管理 API,我们可以在代码中灵活控制事务的执行。在底层,Spring 仍然将事务操作委托给底层的持久化框架来执行。

这种方式事务和业务代码耦合度太高

声明式事务管理

Spring 的声明式事务管理在底层是建立在 AOP 的基础之上的。

其本质是对方法前后进行拦截,然后在目标方法开始之前创建或者加入一个事务,在执行完目标方法之后根据执行情况提交或者回滚事务。

这种方式侵入性小,把事务从业务代码中抽离出来到配置文件中,提供维护性。

 

· 事务管理器

Spring并不直接管理事务,而是提供了多种事务管理器,将事务管理叫给Hibernate等持久化机制所提供的相关平台框架的事务来实现。 

Spring事务管理器的接口是org.springframework.transaction.PlatformTransactionManager。

通过这个接口,Spring为各个平台如JDBC、Hibernate等都提供了对应的事务管理器,但是具体的实现就是各个平台自己的事情了。

spring提供的事务管理器

在使用Spring的事务时,需告诉Spring使用哪一个管理器。

其中DataSourceTransactionManager为JDBC、MyBatis使用的事务管理器。

 

· PlatformTransactionManager中的方法

TransactionStatus getTransaction(TransactionDefinition definition)

根据TransactionDefinition事务定义信息,从事务环境返回一个已存在的事务,或创建一个新的事务。

并用TransactionStatus描述事务状态。

void commit(TransactionStatus status)

根据事务状态提交事务。

如事务状态标识为rollback-only,该方法执行回滚事务的操作。

void rollback(TransactionStatus status)

将事务回滚,当commit方法抛出异常时,rollback会被隐式调用

 

声明式事务管理

基于AOP,使用事务管理器,对业务代码进行事务增强。

· what :做什么增强?

做事务管理器的增强。

告诉Spring使用的是哪一个具体的事务管理器。(如JDBC使用的是DataSourceTransactionManager。)

并对事务管理器做相应的配置。(如DataSourceTransactionManager需注入DataSource对象。)

如下例:

<bean id="txManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager" >
    <property name="dataSource" ref="dataSource" />
</bean>

 

· When:在什么时机增强?

事务应该是环绕增强。如下例: 

<tx:advice transaction-manager="txManager" id="txAdvice">
    <tx:attributes>
        <tx:method name="transfer"/>
    </tx:attributes>
</tx:advice>

<tx:advice>中配置transaction-manager属性,该管理器做环绕增强。

<tx:attributes>元素中<tx:method>的属性配置,可理解为对TransactionDefinition对象做属性配置以及一些额外的配置,以便事务管理器获取事务,做回滚相关操作。

其name属性值为方法名,表示在对该方法做事务增强,可使用通配符*。

更多具体配置可参考文末。

 

· Where:在哪里做增强?

通过AOP做相关配置,如下例:

<aop:config>
    <aop:pointcut id="txPoint" expression="execution(* com.hanaii.spring_tx.service.*Service.*(..))"/>
    <aop:advisor advice-ref="txAdvice" pointcut-ref="txPoint" />
</aop:config>

对切入点进行配置后,我们还需要通过<aop:advisor>将advice与pointcut关联起来。

这样Spring才知道从哪个地方where,什么时候when,做什么样what的切入。

 

<tx:method>中的属性

 

· 事务传播行为

Spring在TransactionDefinition接口中规定了7种类型的事务传播行为,

它们规定了事务方法和事务方法发生嵌套调用时事务如何进行传播。

 PROPAGATION_REQUIRED

如果当前没有事务,就新建一个事务,

如果已经存在一个事务中,加入到这个事务中。这是最常见的选择。

PROPAGATION_SUPPORTS

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

PROPAGATION_MANDATORY

使用当前的事务,如果当前没有事务,就抛出异常。

PROPAGATION_REQUIRES_NEW

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

PROPAGATION_NOT_SUPPORTED

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

PROPAGATION_NEVER

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

PROPAGATION_NESTED 

如果当前存在事务,则在嵌套事务内执行。如果当前没有事务,则执行与PROPAGATION_REQUIRED类似的操作。

 

 · CRUD通用的环绕增强

<tx:advice transaction-manager="txManager" id="txAdvice">
	<tx:attributes>
		<tx:method name="get*" read-only="true"/>
		<tx:method name="find*" read-only="true"/>
		<tx:method name="query*" read-only="true"/>
		<tx:method name="*"/>
	</tx:attributes>
</tx:advice>

 

· 使用注解配置事务

1、在Spring配置文件中配置注解解析器和事务管理器

<bean id="txManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager" >
		<property name="dataSource" ref="dataSource" />
</bean>

<tx:annotation-driven transaction-manager="txManager"/>

 

2、使用@Transactional标签进行标注

该注解源代码:

public @interface Transactional {
    String value() default "";

    Propagation propagation() default Propagation.REQUIRED;

    Isolation isolation() default Isolation.DEFAULT;

    int timeout() default -1;

    boolean readOnly() default false;

    Class<? extends Throwable>[] rollbackFor() default {};

    String[] rollbackForClassName() default {};

    Class<? extends Throwable>[] noRollbackFor() default {};

    String[] noRollbackForClassName() default {};
}

该注解标注在类上时,其配置对该类所有方法生效。

同时,标注在方法时,可对某一方法进行局部的配置(如查询方法配置read-only)。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值