Spring事务的实现方式

什么是事务?

说到事务,一般指的都是数据库中的事务。

  • 是数据库操作的最小工作单元,是作为单个逻辑工作单元执行的一系列操作。
  • 这些操作作为一个整体一起向系统提交,要么都执行、要么都不执行。
  • 事务是一组不可再分割的操作集合(工作逻辑单元)。

数据具有以下特性(ACID)

  • 原子性(Atomicity) 事务包含的所有操作要么全部成功,要么全部失败回滚,因此事务的操作如果成功就必须要完全应用到数据库,如果操作失败则不能对数据库有任何影响。
  • 一致性(Consistency) 事务必须使数据库从一个一致性状态变换到另一个一致性状态,也就是说一个事务执行之前和执行之后都必须处于一致性状态。
  • 隔离性(Isolation) 隔离性是当多个用户并发访问数据库时,比如同时操作同一张表时,数据库为每一个用户开启的事务,不能被其他事务的操作所干扰,多个并发事务之间要相互隔离。
  • 持久性(Durability) 事务一旦被提交了,那么对数据库中的数据的改变就是永久性的,即便是在数据库系统遇到故障的情况下也不会丢失提交事务的操作。

事务的隔离级别

  • Read uncommitted(未授权读取、读未提交) 如果一个事务已经开始写数据,则另外一个事务则不允许同时进行写操作,但允许其他事务读此行数据。
  • Read committed(授权读取、读提交 读取数据的事务允许其他事务继续访问该行数据,但是未提交的写事务将会禁止其他事务访问该行。
  • Repeatable read(可重复读取) 可重复读是指在一个事务内,多次读同一数据,读到的数据结果是一样的。(Mysql默认的实现)
  • Serializable(序列化) 它要求事务序列化执行,事务只能一个接着一个地执行,但不能并发执行。

在这里插入图片描述

spring实现事务

在这里插入图片描述

  • TracsactionDefinition定义了事务的一些传播行为,隔离级别
  • PlatformTracsactionManager(事务管理器)
  • TracsactionStatus用来获取事务的运行状态

Spring事务的转播机制

  • REQUIRED(Spring默认的事务传播类型) 如果当前没有事务,则自己新建一个事务,如果当前存在事务,则加入这个事务。
  • SUPPORTS 当前存在事务,则加入当前事务,如果当前没有事务,就以非事务方法执行。
  • MANDATORY 当前存在事务,则加入当前事务,如果当前事务不存在,则抛出异常。
  • REQUIRES_NEW 创建一个新事务,如果存在当前事务,则挂起该事务。
  • NOT_SUPPORTED 始终以非事务方式执行,如果当前存在事务,则挂起当前事务。
  • NEVER 不使用事务,如果当前事务存在,则抛出异常。
  • NESTED 如果当前事务存在,则在嵌套事务中执行,否则REQUIRED的操作一样(开启一个事务—调用方可以catch被调用方的异常,这样调用方事务不受影响,被调用方回退。如果调用方出现了异常,那么两个事务都会回退。)

ps:在事务中,如果异常被捕获,是不会发生回退的。Spring事务的隔离级别和数据库的一样,默认隔离级别是跟数据库保持一致。

编程式实现

一、使用DataSourceTransactionManager ,该类实现了PlatformTracsactionManager
在这里插入图片描述
1、创建Spring工程时记得导入下面的依赖

  <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-jdbc</artifactId>
            <version>5.3.4</version>
   </dependency>

2、配置Xml

  <context:property-placeholder location="classpath:database.properties"></context:property-placeholder>
 <!--数据源-->
    <bean id="datasource" class="com.mchange.v2.c3p0.ComboPooledDataSource">
        <property name="jdbcUrl" value="${jdbc.url}"></property>
        <property name="driverClass" value="${jdbc.driver}"></property>
        <property name="user" value="${jdbc.username}"></property>
        <property name="password" value="${jdbc.password}"></property>
    </bean>

    <bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
        <property name="dataSource" ref="datasource"></property>
        <property name="configLocation" value="classpath:mybatis-conf.xml"></property>
    </bean>

    <bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
        <property name="sqlSessionFactoryBeanName" value="sqlSessionFactory"></property>
        <property name="basePackage" value="ex.hql.dao"></property>
    </bean>

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

    <bean id="template"
          class="org.springframework.jdbc.core.JdbcTemplate">
        <!-- 注入连接信息 -->
        <property name="dataSource" ref="datasource">
        </property>
    </bean>

3、代码

    public Integer deleteById(int id) {
        DefaultTransactionDefinition transactionDefinition=new DefaultTransactionDefinition();
        //事务的隔离级别
       transactionDefinition.setIsolationLevel(TransactionDefinition.ISOLATION_DEFAULT);
       //事务的传播级别
       transactionDefinition.setPropagationBehavior(TransactionDefinition.PROPAGATION_REQUIRED);
        transactionManager.setDataSource(jdbcTemplate.getDataSource());
       TransactionStatus status = transactionManager.getTransaction(transactionDefinition);
       try {
           ----这里写你的逻辑代码----
			//提交事务
          transactionManager.commit(status);
       }catch (Exception e){
       //发生错误时候回滚
            transactionManager.rollback(status);
       }

二、使用TransactionTemplate
在这里插入图片描述
内部有个模板方法
在这里插入图片描述
最主要的执行方法还是
在这里插入图片描述
可以通过匿名内部类或者Lambada表达式方式实现。

1、声明Bean

    <bean id="transactionTemplate"
          class="org.springframework.transaction.support.TransactionTemplate">
        <property name="transactionManager">
            <ref bean="transCationManage"/>
        </property>
    </bean>

2、代码

    public Object doSomething(){
      return  transactionTemplate.execute(new TransactionCallback<Object>() {
            public Object doInTransaction(TransactionStatus status) {
                --这里写你的逻辑代码--
                return null;
            }
        });
    }

声明式事务

使用注解 @Transactional
在这里插入图片描述

1、配置文件(其他不变)
代理类的话proxy-target-class为true

 <tx:annotation-driven transaction-manager="transCationManage" proxy-target-class="true"></tx:annotation-driven>

2、代码

 @Transactional
    public Object doSomething(){
       --写你的逻辑代码--
      return null;
    }

ps:@Transactional只能作用在public修饰的方法上。

两种方式的比较

编程式的实现方式的粒度更细,使用注解只用作用在方法上,粒度更粗。

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值