05-Spring-事务管理


 

1.事务管理

  1. 概念:

    事务是数据库操作最基本单元,逻辑上一组操作,要么都成功,要么都失败,

    如果有一个失败操作那么所有的操作都失败

  2. 事务四个特性(ACID)

  • 原子性(Atomicity):

    指事务是一个不可分割的工作单位,事务中的操作要么都发生,要么都不发生。

  • 一致性(Consistency):

    事务前后数据的完整性必须保持一致。

  • 隔离性(Isolation):

    事务的隔离性是多个用户并发访问数据库时,数据库为每一个用户开启的事务,不能被其他事务的操作数据所干扰,多个并发事务之间要相互隔离。

  • 持久性(Durability):

    持久性是指一个事务一旦被提交,它对数据库中数据的改变就是永久性的,接下来即使数据库发生故障也不应该对其有任何影响

事务的运行

  1. 开启事务
  2. 进行业务操作
  3. 没有发生异常,提交事务
  4. 发生异常,进行事务回滚

2.声明式事务管理

2.1 实现步骤
  1. 创建配置事务管理器

    DataSourceTransactionManage (针对JdbcTemplate或Mybatis)

  2. 开启事务

    @EnableTransactionManagement 或者配置 < tx:annotation-driven/>

  3. 在需要进行事务处理的类或者方法上添加事务注解

    @Transactional

(1)基于注解实现

配置类:SpringConfig.java

@Configuration
@ComponentScan(basePackages = {"com.potato"})
@EnableTransactionManagement  // 2.开启事务注解
public class SpringConfig {

    //1.创建配置事务管理器 DataSourceTransactionManager 
    @Bean(name = "transactionManager")
    public DataSourceTransactionManager transactionManager(DataSource dataSource) {
        return new DataSourceTransactionManager(dataSource);
    }
    
    @Bean(name = "dataSource")
    public DataSource createDataSource() {
        DruidDataSource dataSource = new DruidDataSource();
        dataSource.setDriverClassName("com.mysql.jdbc.Driver");
        dataSource.setUrl("jdbc:mysql://127.0.0.1:3306/spring5");
        dataSource.setUsername("root");
        dataSource.setPassword("root");
        return dataSource;
    }
    @Bean(name = "jdbcTemplate")
    public JdbcTemplate createDataSource(DataSource dataSource) {
        JdbcTemplate jdbcTemplate = new JdbcTemplate(dataSource);
        return jdbcTemplate;
    }
}

需要事务处理的类:BankServiceImpl.java

//3.在需要进行事务处理的类或者方法上添加事务注解  
@Transactional
@Override
public Integer transferAccounts(String saveAccount, String takeAccount, int money) {
    Integer take = bankDao.take(takeAccount, money);
    Integer save = bankDao.save(saveAccount, money);

    return take == save ? (take != 0 ? 1 : 0) : 0;
}
(2)基于xml配置文件实现

配置文件

<context:component-scan base-package="com.potato"/>
<bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource">
    <property name="driverClassName" value="com.driver.jdbc.mysql"/>
    <property name="url" value="jdbc:mysql://127.0.0.1:3306/spring5"/>
    <property name="username" value="root"/>
    <property name="password" value="root"/>
</bean>
<bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
    <constructor-arg ref="dataSource"/>
</bean>

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

<!--    2.开启事务注解-->
<tx:annotation-driven transaction-manager="transactionManager"/>
2.2 Spring事务管理API :PlatformTransactionManager接口

在这里插入图片描述

PlatformTransactionManager:事务管理的接口,有多个不同的实现类分别针对不同的数据处理框架

DataSourceTransactionManager :JdbcTemplate、Mybatis

HibernateTransactionManager:Hibernate

2.3 @Transactional 相关参数

在这里插入图片描述

propagation:事务传播行为

isolation:事务隔离级别

timeout:超时时间

readOnly:是否只读

rollbackFor:发生指定的异常则回滚

noRollbackFor:发生指定的异常则不回滚

2.4 传播行为:propagation
传播属性 解析
REQUIRED(默认) 如果当前没有事务,就新建一个事务,如果已经存在一个事务中,
就继续使用该事务。这是最常见的选择。
REQUIRES_NEW 新建事务,如果当前存在事务,把当前事务挂起。
SUPPORTS 支持当前事务,如果当前没有事务,就以非事务方式执行。
MANDATORY 使用当前的事务,如果当前没有事务,就抛出异常。
NOT_SUPPORTED 以非事务方式执行操作,如果当前存在事务,就把当前事务挂起。
NEVER 以非事务方式执行,如果当前存在事务,则抛出异常。
NESTED 如果当前存在事务,则在嵌套事务内执行。如果当前没有事务,
则执行与REQUIRED类似的操作。
2.5 隔离级别:isolation
  1. 不考虑隔离性 则会产生以下三个问题

    • 脏读:

      在多事务之间:一个未提交的事务读取到另一个未提交事务的数据

    • 不可重复读

      两个事务,事务A与事务B,事务A在自己执行的过程中,执行了两次相同查询,

      第一次查询事务时B未提交,第二次查询事务时B已提交,从而造成两次查询结果不一样

    • 幻读(虚读)

      在一个事务的两次查询中数据笔数不一致,例如有一个事务查询了几列(Row)数据,而另一个事务却在此时插入了新的几列数据,先前的事务在接下来的查询中,就会发现有几列数据是它先前所没有的。

  2. 隔离级别参数

    属性值 脏读 不可重复读 幻读
    READ_UNCOMMITTED(读未提交)
    READ_COMMITTED(读以提交)
    REPEATABLE_READ(可重复读) (默认)
    SERIALIZABLE(串行化)
2.6 其他参数
  • timeout:超时时间 秒为单位

    事务在一定时间内进行提交,如果不提交则进行回滚

  • readOnly:是否只读

    (1)1.读:查询操作 2.写:增删改操作

    (2)默认值为 false, 表示可以增删改查

    (3)设置为true 则是只读操作

  • rollbackFor:回滚

    (1)设置出现哪些异常需要进行事务回滚

  • noRollbackFor:不回滚

    (1)设置出现哪些异常不需要进行事务回滚

3.编程式事务管理

  • 实现步骤

    1.配置事务管理器

    2.配置通知

    3.配置切入点和切面

    spring-config.xml

    <context:property-placeholder location="druid.properties"/>
    <context:component-scan base-package="com.potato"/>
    <bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource">
        <property name="driverClassName" value="${jdbc.driverClass}"/>
        <property name="url" value="${jdbc.url}"/>
        <property name="username" value="${jdbc.username}"/>
        <property name="password" value="${jdbc.password}"/>
    </bean>
    <bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
        <constructor-arg ref="dataSource"/>
    </bean>
    
    <!--    1 创建事务管理器-->
    <bean id="transactionManager2" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
        <property name="dataSource" ref="dataSource"/>
    </bean>
    
    <!--    2 配置通知-->
    <tx:advice id="txAdvice">
        <!--    2.1 配置事务参数-->
        <tx:attributes>
            <!--    2.2 指定哪种方法上添加事务    名字以transfer开头的方法添加事务-->
            <tx:method name="transfer*" propagation="REQUIRED"/>
        </tx:attributes>
    </tx:advice>
    
    <!--    3 配置切面-->
    <aop:config>
        <!--    3.1 配置切入点-->
        <aop:pointcut id="pointcut01" 
                      expression="execution(* com.potato.service.BankService.*(..))"/>
        <!--    3.2 配置切面-->
        <aop:advisor advice-ref="txAdvice" pointcut-ref="pointcut01"/>
    </aop:config>
    

原创文章,作者:ItWorker,如若转载,请注明出处:https://blog.ytso.com/289035.html

(0)
上一篇 2022年9月12日
下一篇 2022年9月12日

相关推荐

发表回复

登录后才能评论