欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

Spring中的事务控制

程序员文章站 2024-01-14 10:21:58
...

Spring中的事务控制

Spring中提供了分层设计的业务层事务处理解决方案

Spring中的事务控制也是基于AOP的,它既可以使用编程的方式实现,也可以使用配置的方式实现

所谓事务控制,就是根据我们给定的事务规则来执行提交或回滚操作。

在这里再说一次事务的四个特性:ACID

  • 原子性:(Atomicity)事务是一个不可分割的整体,要么全部完成,要么全部失败
  • 一致性:(Consistency)一个事务的完成前后,系统总量仍要保持一致
  • 隔离性:(lsolation)多个事务处理同一个数据时,每个事务都应该是隔离开的,防止数据损害
  • 持久性:(durability)事务一旦完成,事务的结果都会被保存在持久化容器中

Spring并不会直接管理事务,而是提供了多种事务管理器:

PlatformTransactionManager

这个接口是Spring中的事务管理器,它里面提供了我们常用的操作事务的方法,

  • 获取事务的状态信息:

    • TransactionStatus getTransaction(@Nullable TransactionDefinition var1) throws TransactionException;
      
  • 提交事务:

    • void commit(TransactionStatus var1) throws TransactionException;
      
  • 回滚事务:

    • void rollback(TransactionStatus var1) throws TransactionException;
      

Spring提供了PlatformTransactionManager接口,然而具体的实现还是各大平台(JDBC、Hibernate等)自己来完成的。

DataSourceTransactionManager:JDBC或MyBatis使用(所在包:package org.springframework.jdbc.datasource;)

HibernateTransactionManager:Hibernate使用(所在包:package org.springframework.orm.hibernate5;)

注意上面获取事务信息状态的接口方法getTransaction它的参数是一个TransactionDefinition类型,在这个接口中,就定义了一些基本的事务属性

  • 获取事务对象名称:

    • default String getName()
      
  • 获取事务的隔离级别

    • default int getIsolationLevel()
      
  • 获取事务的传播行为

    • default int getPropagationBehavior()
      
  • 获取事务超时时间

    • default int getTimeout()
      
  • 获取事务是否只读

    • default boolean isReadOnly()
      

事务的属性我们可以总结为五个方面:传播行为、隔离规则、回滚规则、事务超时、是否只读

Spring的事务传播行为:

spring事务的传播行为指的是:当多个事务同时存在的时候,spring如何处理这些事务的行为。共有七种:

PROPAGATION_REQUIRED:如果当前没有事务,就创建一个新事务,如果当前存在事务,就加入该事务,该设置是最常用的设置。

PROPAGATION_SUPPORTS:支持当前事务,如果当前存在事务,就加入该事务,如果当前不存在事务,就以非事务执行。‘

PROPAGATION_MANDATORY:支持当前事务,如果当前存在事务,就加入该事务,如果当前不存在事务,就抛出异常。

PROPAGATION_REQUIRES_NEW:创建新事务,无论当前存不存在事务,都创建新事务。

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

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

PROPAGATION_NESTED:如果当前存在事务,则在嵌套事务内执行。如果当前没有事务,则按REQUIRED属性执行。

Spring中的隔离级别:

  • ISOLATION_DEFAULT:这是个 PlatfromTransactionManager 默认的隔离级别,使用数据库默认的事务隔离级别。
  • ISOLATION_READ_UNCOMMITTED:读未提交,允许另外一个事务可以看到这个事务未提交的数据。
  • ISOLATION_READ_COMMITTED:读已提交,保证一个事务修改的数据提交后才能被另一事务读取,而且能看到该事务对已有记录的更新。
  • ISOLATION_REPEATABLE_READ:可重复读,保证一个事务修改的数据提交后才能被另一事务读取,但是不能看到该事务对已有记录的更新。
  • ISOLATION_SERIALIZABLE:一个事务在执行的过程中完全看不到其他事务对数据库所做的更新。

基于XML配置的事务

事务配置相关的标签及其属性:

  • 事务配置通知标签 tx:advice
    • 属性 id:唯一标识
    • 属性 transaction-manager:配置事务管理类的id
  • 事务属性配置子标签 tx:attributes
    • 子标签事务方法 tx:method
      • 属性 name:指定方法的名称,支持通配符*(必须,*表示所有方法)
      • 属性 propagation:指定事务的传播行为(默认REQUIRED)
      • 属性 isolation:指定事务的隔离级别(默认采用数据库的隔离级别)
      • 属性 read-only:指定是否为只读(默认false)
      • 属性 timeout:指定事务的超时时间(默认-1永不超时,以秒为单位)
      • 属性 no-rollback-for:指定一个异常,设置后,当发生该异常时,事务不会回滚
      • 属性 rollback-for:指定一个异常,设置后,当发生该异常时,事务回滚
  • aop切面配置子标签 aop:config
    • 子标签 aop:advisor:将切入点和事务通知相关联
      • 属性 advice-ref:引用通知
      • 属性 pointcut-ref:引用切入点

只有关键代码,全部流程请参考上一篇(Spring中的AOP

配置bean.xml

<?xml version="1.0" encoding="UTF-8" ?>
<!-- 添加约束tx-->
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:aop="http://www.springframework.org/schema/aop"
       xmlns:tx="http://www.springframework.org/schema/tx"
       xsi:schemaLocation="
       http://www.springframework.org/schema/beans
       https://www.springframework.org/schema/beans/spring-beans.xsd
       http://www.springframework.org/schema/aop
       https://www.springframework.org/schema/aop/spring-aop.xsd
       http://www.springframework.org/schema/tx
       https://www.springframework.org/schema/tx/spring-tx.xsd
">
    <!--配置事务管理器 (直接使用jdbc提供的实现类)-->
    <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
        <!--注入数据源-->
        <property name="dataSource" ref="dataSource"/>
    </bean>
    <!--配置事务的通知-->
    <tx:advice id="txAdvice" transaction-manager="transactionManager">
        <!--配置事务的属性-->
        <tx:attributes>
            <!-- 配置find和get开头的方法传播行为为SUPPORTS(有就在事务中,没有就在非事务中执行),并且设置为只读-->
            <tx:method name="find*" propagation="SUPPORTS" read-only="true"/>
            <tx:method name="get*" propagation="SUPPORTS" read-only="true"/>
            <!-- 不属于查询的方法,如增删改,就要保证在事务中进行,并且不为只读-->
            <tx:method name="*" propagation="REQUIRED" read-only="false"/>
        </tx:attributes>
    </tx:advice>
    <!--配置aop-->
    <aop:config>
        <aop:pointcut id="pointcut2" expression="execution(* com.zxy.service.impl.*.*(..))"/>
        <!--配置切入点和事务通知关联-->
        <aop:advisor advice-ref="txAdvice" pointcut-ref="pointcut2"/>
    </aop:config>
</beans>

对比上一篇,使用aop,自定义的事务管理类,来完成对事务的控制;到现在我们只需要在xml文件中配置一下,即可实现 让我们的代码在事务中执行

基于注解的事务配置

不光可以使用配置文件的方式,Spring中还提供了注解的方式,比起XML更加简单,使用一个注解,就可以保证方法在事务中运行

@Transactional :

  • 使用在接口上:当前接口所有实现类中重写接口的方法有事务的支持
  • 使用在类上:当前类中的所有方法有事务的支持
  • 使用在方法上:当前方法有事务的支持

(同时出现时的优先级:方法 > 类 > 接口)

在转账的实现类上增加一个注解:

    @Transactional
    @Override
    public void transfer(String name1, String name2, Double money) {
        // 获得转账两人信息
        Account source = accountMapper.findByName(name1);
        Account target = accountMapper.findByName(name2);
        source.setMoney(source.getMoney() - money);
        target.setMoney(target.getMoney() + money);
        // 执行source减少和target增加的更新操作
        accountMapper.update(source);
//        System.out.println(10 / 0);
        accountMapper.update(target);
        System.out.println("转账业务完成");
    }

@EnableTransactionManagement:开启Spring对注解的支持

在配置类中增加一个注解

···
@EnableTransactionManagement
public class SpringConfig {···

此时使用Spring中为我们提供的两个注解,就完成了事务的功能

当然Transactional注解中也为我们提供了一些属性:

    @AliasFor("transactionManager")
    String value() default "";// 指定使用的事务管理器

    @AliasFor("value")
    String transactionManager() default "";

    String[] label() default {};

    Propagation propagation() default Propagation.REQUIRED;// 指定事务的传播行为

    Isolation isolation() default Isolation.DEFAULT;// 指定事务的隔离级别

    int timeout() default -1;// 指定事务的超时时间

    String timeoutString() default "";

    boolean readOnly() default false;// 指定是否为只读

    Class<? extends Throwable>[] rollbackFor() default {};// 指定会发生回滚的异常,数组

    String[] rollbackForClassName() default {};// 指定会发生回滚的异常的类名,数组

    Class<? extends Throwable>[] noRollbackFor() default {};// 指定不会发生回滚的异常,数组

    String[] noRollbackForClassName() default {};// 指定不会发生回滚的异常的类名,数组