Spring的事务管理

Spring的事物管理的高层级抽象有三个:

  1. PlatformTransactionManager
  2. TransactionDefinition
  3. TransactionStstus

这三个接口之间的关系:PlantformTransactionManager根据TransactionDefinition进行事物管理,管理过程中会出现许多的事物状态,每个状态信息通过TransactionStstus展示。

 

1)不同平台的不同实现

PlatformTransactionManager的实现类

org.springframework.jdbc.DataSourceTransactionManager

Org.springframework.orm.hibernate3HibernateTransactionManager

org.springframework.jdc.JdoTrasactionManager

org.springframework.transaction.jta.JtaTransactionManager

针对不同的事务,我们要选用不同的实现。

 

  1. 事物的隔离级别
  1. Read uncommitted读未提交,顾名思义,就是一个事务可以读取另一个未提交事务的数据。
  2. Read committed读提交,顾名思义,就是一个事务要等另一个事务提交后才能读取数据。
  3. Repeatable read重复读,就是在开始读取数据(事务开启)时,不再允许修改操作
  4. Serializable 序列化Serializable 是最高的事务隔离级别,在该级别下,事务串行化顺序执行,可以避免脏读、不可重复读与幻读。但是这种事务隔离级别效率低下,比较耗数据库性能,一般不使用。
package org.springframework.transaction.annotation;

public enum Isolation {
    DEFAULT(-1),
    READ_UNCOMMITTED(1),
    READ_COMMITTED(2),
    REPEATABLE_READ(4),
    SERIALIZABLE(8);

    private final int value;

    private Isolation(int value) {
        this.value = value;
    }

    public int value() {
        return this.value;
    }
}

 

 

3)事务的传播行为(一个业务的执行调用了另一个业务层事务,事务之间的关系如何处理)

SPring定义了7种事物的传播行为

/* 处于同一个事务中 */

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; // 以非事务的方式运行,如果当前事务存在,则直接抛出异常

/* 一个事物,不完全成功可恢复到Savepoint,可选择后续操作 */

int PROPAGATION_NESTED = 6; // 如果当前事务存在,则嵌套事务执行。依赖于JDK3.0 提供的SavePoint技术。删除客户,删除订单,在删除客户后,设置Savepoint,执行删除订单,删除订单和删除客户处在同一个事物中,如果删除订单失败,事务回滚Savepoint,由用户来控制事务提交还是回滚。

 

4)Spring的事物管理方式

  1. 编程式的事物管理。在代码中,通过TransactionTempalte来手动管理事务
  2. 声明式事务管理,在配置文件中,对我们定义的方法进行事务管理,基于AOP实现的。

 

编排式事物管理

<bean id="accountDao" class="com.andy.transaction.AccountDaoImpl">
    <property name="jdbcTemplate" ref="jdbcTemplate"/>
</bean>

<bean id="accountService" class="com.andy.transaction.AccountServiceImpl">
    <property name="account" ref="accountDao"/>
    <property name="transactionTemplate" ref="transactionTemplate"/>
</bean>

<!--  配置连接池 -->
<bean id="datasource" class="com.mchange.v2.c3p0.ComboPooledDataSource">
    <property name="driverClass" value="com.mysql.cj.jdbc.Driver"/>
    <property name="jdbcUrl" value="jdbc:mysql:///transactiondb?serverTimezone=Asia/Shanghai"/>
    <property name="user" value="root"/>
    <property name="password" value="Andy"/>
</bean>

<bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
    <property name="dataSource" ref="datasource"/>
</bean>

<!-- 事务管理的模板   -->
<bean id="transactionTemplate" class="org.springframework.transaction.support.TransactionTemplate">
    <property name="transactionManager" ref="dataSourceTransactionManager"/>
</bean>

<!--  事物管理器 用来管理jdbc操作的事务管理器 -->
<bean id="dataSourceTransactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager" >
    <property name="dataSource" ref="datasource"/>
</bean>

将事务管理器注入事务模板,再将事务模板注入业务实现类,在业务实现类中使用事务管理模板的execute方法来执行操作。

/**
 * 业务实现层
 */

public class AccountServiceImpl implements AccountService {
    
    @Autowired
    private AccountDaoImpl account;
    
    private TransactionTemplate transactionTemplate;
    
    @Override
    public void transfer(final String out,final String in,final double num) {
        transactionTemplate.execute(new TransactionCallbackWithoutResult() {
            @Override
            protected void doInTransactionWithoutResult(TransactionStatus transactionStatus) {
                account.outTransfer(out, num);
               // int a= 1/0;
                account.inTransfer(in, num);
            }
        });
    }
    
    public void setAccount(AccountDaoImpl account) {
        this.account = account;
    }
    public void setTransactionTemplate(TransactionTemplate transactionTemplate) {
        this.transactionTemplate = transactionTemplate;
    }
}

 

4)声明式事务管理。无需更改类的结构,仅需要在xml配置文件中,声明事务管理,并配置即可。使用了org.springframework.transaction.interceptor.TransactionProxyFactoryBean

<bean id="accountDao" class="com.andy.claimTransaction.AccountDaoImpl">
    <property name="jdbcTemplate" ref="jdbcTemplate"/>
</bean>

<bean id="accountService" class="com.andy.claimTransaction.AccountServiceImpl">
    <property name="account" ref="accountDao"/>
</bean>

<!--  配置连接池 -->
<bean id="datasource" class="com.mchange.v2.c3p0.ComboPooledDataSource">
    <property name="driverClass" value="com.mysql.cj.jdbc.Driver"/>
    <property name="jdbcUrl" value="jdbc:mysql:///transactiondb?serverTimezone=Asia/Shanghai"/>
    <property name="user" value="root"/>
    <property name="password" value="Andy"/>
</bean>

<bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
    <property name="dataSource" ref="datasource"/>
</bean>

<!-- 事务管理器  -->
<bean id="dataSourceTransactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
    <property name="dataSource" ref="datasource"/>
</bean>

<bean id="transactionProxyFactoryBean" class="org.springframework.transaction.interceptor.TransactionProxyFactoryBean">
    <!-- 事务管理器-->
    <property name="transactionManager" ref="dataSourceTransactionManager"/>
    <!-- 目标-->
    <property name="target" ref="accountService"/>
    <!--    针对接口代理     -->
    <property name="proxyInterfaces" value="com.andy.claimTransaction.AccountService"/>
    <!--
    事务管理属性
    针对目标方法设置具体需要事务管理的方法名,隔离级别,传播行为,是否只读等信息
    -->
    <property name="transactionAttributes">
        <props>
            <!-- 设置需要代理的方法-->
            <!-- PROPAGATION 事务的传播行为  -->
            <!-- ISOLUATION  事务隔离级别  -->
            <!-- readOnly    事务只读,不能有更新操作  -->
            <!-- -exception  事务出现异常就回滚  -->
            <!-- +exception  事务出现异常也执行  -->
            <prop key="transfer"></prop>
        </props>
    </property>
</bean>

缺点是需要为每个类创建事务代理bean,开发量巨大

 

5)基于tx配置,为目标类创建事务代理

  1. 导入aop和tx命名空间
  2. 定义事务管理器
  3. 利用tx标签创建通知
  4. 使用AOP自动代理配置tx:Advice的代理

<bean id="accountDao" class="com.andy.claimTransaction.AccountDaoImpl">
    <property name="jdbcTemplate" ref="jdbcTemplate"/>
</bean>

<bean id="accountService" class="com.andy.claimTransaction.AccountServiceImpl">
    <property name="account" ref="accountDao"/>
</bean>

<!--  配置连接池 -->
<bean id="datasource" class="com.mchange.v2.c3p0.ComboPooledDataSource">
    <property name="driverClass" value="com.mysql.cj.jdbc.Driver"/>
    <property name="jdbcUrl" value="jdbc:mysql:///transactiondb?serverTimezone=Asia/Shanghai"/>
    <property name="user" value="root"/>
    <property name="password" value="Andy"/>
</bean>

<bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
    <property name="dataSource" ref="datasource"/>
</bean>

<!-- 事务管理器  -->
<bean id="dataSourceTransactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
    <property name="dataSource" ref="datasource"/>
</bean>

<!--    使用tx定义事务管理-->
<tx:advice id="txAdvice" transaction-manager="dataSourceTransactionManager">
    <tx:attributes>
        <tx:method name="transfer"/>
    </tx:attributes>
</tx:advice>

<!-- 使用AOP进行自动代理 -->
<aop:config>
    <!-- 定义切点 -->
    <aop:pointcut id="pointcut" expression="execution(* com.andy.claimTransaction.AccountServiceImpl.transfer(..))"/>
    <!-- 定义切面 -->
    <aop:advisor advice-ref="txAdvice" pointcut-ref="pointcut"/>
</aop:config>

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations = "classpath:appClaimTransaction.xml")
public class ClaimTransactionTest {
    
    @Autowired
    @Qualifier("accountService")
    private AccountService accountService;
    
    @Test
    public void test(){
        accountService.transfer("aaa","bbb",1);
    }
}

 

 

基于注解的事物管理

  1. 在需要管理的类或者方法上添加注解@Transactional
  2. 注解驱动注解管理
<bean id="accountDao" class="com.andy.AnnotationTransaction.AccountDaoImpl">
    <property name="jdbcTemplate" ref="jdbcTemplate"/>
</bean>

<bean id="accountService" class="com.andy.AnnotationTransaction.AccountServiceImpl">
    <property name="account" ref="accountDao"/>
</bean>

<!--  配置连接池 -->
<bean id="datasource" class="com.mchange.v2.c3p0.ComboPooledDataSource">
    <property name="driverClass" value="com.mysql.cj.jdbc.Driver"/>
    <property name="jdbcUrl" value="jdbc:mysql:///transactiondb?serverTimezone=Asia/Shanghai"/>
    <property name="user" value="root"/>
    <property name="password" value="Andy"/>
</bean>

<bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
    <property name="dataSource" ref="datasource"/>
</bean>

<!-- 事务管理器  -->
<bean id="dataSourceTransactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
    <property name="dataSource" ref="datasource"/>
</bean>

<!-- 注解事务管理   -->
<tx:annotation-driven transaction-manager="dataSourceTransactionManager" />

@Override
@Transactional(isolation = Isolation.DEFAULT,propagation = Propagation.REQUIRED ,readOnly = false ,noRollbackFor = ArithmeticException.class)
public void transfer(final String out,final String in,final double num) {
    transactionTemplate.execute(new TransactionCallbackWithoutResult() {
        @Override
        protected void doInTransactionWithoutResult(TransactionStatus transactionStatus) {
            account.outTransfer(out, num);
            int a= 1/0;
            account.inTransfer(in, num);
        }
    });
}

 

小结:

TransactionTemplate 编程式事务管理 了解

TransactionProxyFactoryBean 声明式事务管理 了解

基于tx和aop的xml配置 事务管理 重点掌握

基于tx以及@Transactional的事物管理 必须掌握

 

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值