Spring框架的使用指南(二)声明式事务篇

Spring框架的使用指南(二)声明式事务篇

前言:Spring除了提供IOC和AOP两大功能外,还提供了事务管理的功能。

所谓事务就是保证一个操作只有两种状态,完成状态或者初始状态,不会出现完成了99%的情况。我们为什么需要事务呢?用个最经典例子说明一下,甲在银行转账,账户有1000元,转给乙500元,如果转账成功,那么甲账户只有500元,乙账户增加500元。但是如果甲转账时,银行停电了呢,甲账户少了500元,但乙账户却因为停电中断了转账操作导致账户还是原来的数额。这样的情况明显是不合理,既然转账失败了,那钱就应该退回原账户才对。所以这时候我们就要用事务来保证转账操作要么成功,甲少了500元,乙增加500元,要么转账失败,甲还是原来的数额,乙也是原来的数额。

Spring事务

Spring提供了对编程式事务和声明式事务的支持,编程式事务允许用户在代码中精确定义事务的边界,而声明式事务(基于AOP)有助于用户将操作与事务规则进行解耦。
简单地说,编程式事务侵入到了业务代码里面,但是提供了更加详细的事务管理;而声明式事务由于基于AOP,所以既能起到事务管理的作用,又可以不影响业务代码的具体实现。

事务的四个特性

1.原子性,事务由一系列动作组成,但这个操作无法被继续分割。原子性保证动作要么全部完成,要么一个都没有完成。

2.一致性,事务一旦完成,无论是成功还是失败,所有业务数据都是一致的,不能出现甲转了500,但乙却没有增加500的情况。

3.隔离性,可能有多个事务同事处理同一个数据,应保证事务之间隔离性,防止数据损坏。

4.持久性,一旦事务完成,不管发生什么系统错误,事务结果都不能再可变动,通常会将事务结果写入持久化存储器中。

事务的隔离级别

隔离级别定义了一个事务可能受其他并发事务影响的程度。 当多个事务并发处理相同的数据时就有可能出现下列问题。

脏读:后一个事务读取了前一个事务修改了却没有提交的值,如果此时发生异常,数据回滚了,此时后一个事务获得的数据就是无效的。

不可重复读:一个事务执行相同的查询两次或两次以上,但是每次都得到不同的数据时。这通常是因为另一个并发事务在两次查询期间进行了更新。

幻读:幻读与不可重复读类似。它发生在一个事务读取了几行数据,接着另一个并发事务插入了一些数据时。在随后的查询中,第一个事务就会发现多了一些原本不存在的记录。

隔离级别就是为了防止这些现象的出现,而定义的。

事务的传播行为

事务的传播行为是指,当一个事务方法被另一个事务方法调用时,两个事务是怎样的关系。例如方法可能继续在现有事务中运行,也可能开启一个新事务,并在自己的事务中运行。

基于xml配置声明式事务管理

1.引入maven依赖


            
                org.springframework
                spring-jdbc
                5.1.7.RELEASE
            
             
                mysql
                mysql-connector-java
                8.0.16
            

2.配置事务管理器




    
    
        
        
        
        
    
    
		
    
            
    
    
    
    
        
    

    

    
        
            
            
        
    

    
       
        
    


Spring并不直接管理事务,而提供一个Spring事务管理器的接口,通过这个接口,向各个框架提供了对应的事务管理器接口,将具体的事务管理的实现交给了各个框架。

org.springframework.transaction.PlatformTransactionManager

上面的事务管理器是基于jdbc的事务管理器

    
        
    

基于Hibernate的事务管理器


        
    

Java持久化API事务(JPA)

 
        
    

Java原生API事务

如果你没有使用以上所述的事务管理,或者是跨越了多个事务管理源(比如两个或者是多个不同的数据源),你就需要使用JtaTransactionManager:

 
        
    

JtaTransactionManager将事务管理的责任委托给javax.transaction.UserTransaction和javax.transaction.TransactionManager对象,其中事务成功完成通过UserTransaction.commit()方法提交,事务失败通过UserTransaction.rollback()方法回滚。

tx:method标签代表哪些方法需要开启事务管理。

  1. rollback-for属性指定发生什么异常时回滚事务。

  2. propagation属性指定事务的传播行为,默认为REQUIRED
    (1) REQUIRED,,如果当前存在事务,则加入该事务,如果当前不存在事务,则创建一个新的事务。
    (2) SUPPORTS,如果当前存在事务,则加入该事务;如果当前不存在事务,则以非事务的方式继续运行。
    (3) MANDATORY,如果当前存在事务,则加入该事务;如果当前不存在事务,则抛出异常。
    (4) REQUIRES_NEW,重新创建一个新的事务,如果当前存在事务,暂停当前的事务。
    (5) NOT_SUPPORTED,以非事务的方式运行,如果当前存在事务,暂停当前的事务。
    (6) NEVER,以非事务的方式运行,如果当前存在事务,则抛出异常。
    (7) NESTED,和 Propagation.REQUIRED 效果一样。

  3. isolation属性指定事务的隔离级别,默认值为 Isolation.DEFAULT。

PS:若未指定rollback-for属性的值,或值为空,则只有发生RuntimeException异常时才会回滚事务。

基于注解配置声明式事务管理

package FrameWork;

import FrameWork.Advice.myAdvice;
import FrameWork.Service.MusicService;
import FrameWork.Service.UserService;
import FrameWork.ServiceImpl.MusicServiceImpl;
import FrameWork.ServiceImpl.UserServiceImpl;
import FrameWork.bean.Music;
import FrameWork.bean.User;
import org.springframework.context.annotation.*;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.jdbc.datasource.DataSourceTransactionManager;
import org.springframework.jdbc.datasource.DriverManagerDataSource;
import org.springframework.transaction.annotation.EnableTransactionManagement;

@Configuration
@EnableAspectJAutoProxy
@EnableTransactionManagement
public class SpringConfig {

    @Bean
    public Music music()
    {
        return new Music();
    }

    @Bean
    public User user()
    {
        return new User();
    }

    @Bean
    public UserService userService()
    {
        return new UserServiceImpl();
    }

    @Bean
    public MusicService musicService()
    {
        return new MusicServiceImpl();
    }

    @Bean
    public myAdvice myAdvice()
    {
        return new myAdvice();
    }

    @Bean
    public DriverManagerDataSource driverManagerDataSource(){
        DriverManagerDataSource driverManagerDataSource=new DriverManagerDataSource();
        driverManagerDataSource.setDriverClassName("com.mysql.cj.jdbc.Driver");
        driverManagerDataSource.setUrl("jdbc:mysql://localhost:3306/mybatistest?characterEncoding=utf8&useSSL=true&serverTimezone=UTC");
        driverManagerDataSource.setPassword("root");
        driverManagerDataSource.setUsername("root");
        return driverManagerDataSource;
    }

    @Bean
    public JdbcTemplate jdbcTemplate(){
        JdbcTemplate jdbcTemplate=new JdbcTemplate();
        jdbcTemplate.setDataSource(driverManagerDataSource());
        return jdbcTemplate;
    }

    @Bean
    public DataSourceTransactionManager transactionManager(){
        DataSourceTransactionManager dataSourceTransactionManager=new DataSourceTransactionManager();
        dataSourceTransactionManager.setDataSource(driverManagerDataSource());
        return dataSourceTransactionManager;
    }

}

    @Transactional(rollbackFor = Exception.class)
    public void getUser(String name,String sign) throws Exception {
            jdbcTemplate.update("insert into user(name,sign)  values('"+name+"','"+sign+"')");
            throw new Exception("异常");
    }

从代码上可以看出,使用注解配置事务要比xml方便许多。

@EnableTransactionManagement注解代表开启事务支持,标注在配置类上。

@Transactional注解标记使用事务,如果注解在类上,则类中所有public方法使用事务,注解在方法上则只有该方法使用。

PS:@Transactional注解只能对public方法生效,注解到其他非public方法上时不会报错,但不使用事务。

这里是完全采用java配置的,你也可以选择使用xml配置bean和事务管理器,不配置tx:advice和aop:advisor标签,只需要在xml中加入下面的配置


此标签作用相当于@EnableTransactionManagement注解。你现在已经可以使用@Transactional注解配置事务了。

更多关于Spring事务的详细内容,请参考博客:https://www.cnblogs.com/yixianyixian/p/8372832.html

你可能感兴趣的:(Spring,声明式事务,Spring,声明式事务)