Spring【Spring事务(事务简介、Spring事务管理方案 、Spring事务管理器、控制的API、相关配置 )】(七)-全面详解(学习总结---从入门到深化)

 

目录

Spring事务_事务简介

Spring事务_Spring事务管理方案 

Spring事务_Spring事务管理器

Spring事务_事务控制的API

Spring事务_事务的相关配置 

 Spring事务_事务的传播行为

Spring事务_事务的隔离级别 

        Spring事务_注解配置声明式事务


 

 Spring事务_事务简介

 事务:不可分割的原子操作。即一系列的操作要么同时成功,要么同时失败。

开发过程中,事务管理一般在service层,service层中可能会操作多次数据库,这些操作是不可分割的。否则当程序报错时,可能会造 成数据异常。

如:张三给李四转账时,需要两次操作数据库:张三存款减少、李四存款增加。如果这两次数据库操作间出现异常,则会造成数据错 误。

1、准备数据库

CREATE DATABASE `spring` ;
USE `spring`;
DROP TABLE IF EXISTS `account`;
CREATE TABLE `account` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `username` varchar(255) DEFAULT NULL,
  `balance` double DEFAULT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=3 DEFAULT
CHARSET=utf8;
insert  into `account`(`id`,`username`,`balance`) values (1,'张三',1000),(2,'李四',1000);

2、创建maven项目,引入依赖


    
    
        org.mybatis
        mybatis
        3.5.7
    
   
    
        mysql
        mysql-connectorjava
        8.0.26
    
    
    
        com.alibaba
        druid
        1.2.8
    
    
    
        org.springframework
        springcontext
        5.3.13
    
    
        org.springframework
        spring-tx
        5.3.13
    
    
        org.springframework
        springjdbc
        5.3.13
    
    
    
        org.mybatis
        mybatisspring
        2.0.6
    
    
    
        junit
        junit
        4.12
        test
    
    
    
        org.springframework
        springtest
        5.3.13
        test
    

3、创建配置文件



    
    
    
    
        
        
        
        
    
    
        
    
    
        
    

4、编写Java代码

// 账户
public class Account {
    private int id; // 账号
    private String username; // 用户名
    private double balance; // 余额
    
    // 省略getter/setter/tostring/构造方法
}

@Repository
public interface AccountDao {
    // 根据id查找用户
    @Select("select * from account where id = #{id}")
    Account findById(int id);
    // 修改用户
    @Update("update account set balance = #{balance} where id = #{id}")
    void update(Account account);
}

@Service
public class AccountService {
    @Autowired
    private AccountDao accountDao;
    /**
     * 转账
     * @param id1 转出人id
     * @param id2 转入人id
     * @param price 金额
     */
    public void transfer(int id1, int id2, double price) {
        // 转出人减少余额
        Account account1 = accountDao.findById(id1);
        account1.setBalance(account1.getBalance()-price);
        accountDao.update(account1);
        int i = 1/0; // 模拟程序出错
        // 转入人增加余额
        Account account2 = accountDao.findById(id2);
        account2.setBalance(account2.getBalance()+price);
        accountDao.update(account2);
   }
}

5、测试转账

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations="classpath :applicationContext.xml")
public class AccountServiceTest {
    @Autowired
    private AccountService accountService;
    @Test
    public void testTransfer(){
        accountService.transfer(1,2,500);
   }
}

此时没有事务管理,会造成张三的余额减少,而李四的余额并没有 增加。所以事务处理位于业务层,即一个service方法是不能分割的。

Spring事务_Spring事务管理方案 

 在service层手动添加事务可以解决该问题:

@Autowired
private SqlSessionTemplate sqlSession;
public void transfer(int id1, int id2,double price) {
    try{
        // account1修改余额
        Account account1 = accountDao.findById(id1);
        account1.setBalance(account1.getBalance()- price);
        accountDao.update(account1);
        int i = 1/0; // 模拟转账出错
        // account2修改余额
        Account account2 = accountDao.findById(id2);
        account2.setBalance(account2.getBalance()+price);
        accountDao.update(account2);  
        sqlSession.commit();
     }catch(Exception ex){
        sqlSession.rollback();
   }
}

但在Spring管理下不允许手动提交和回滚事务。此时我们需要使用 Spring的事务管理方案,在Spring框架中提供了两种事务管理方案:

1 编程式事务:通过编写代码实现事务管理。

2 声明式事务:基于AOP技术实现事务管理。

在Spring框架中,编程式事务管理很少使用,我们对声明式事务管 理进行详细学习。 Spring的声明式事务管理在底层采用了AOP技术,其最大的优点在 于无需通过编程的方式管理事务,只需要在配置文件中进行相关的 规则声明,就可以将事务规则应用到业务逻辑中。 

 使用AOP技术为service方法添加如下通知:

 

Spring事务_Spring事务管理器

 Spring依赖事务管理器进行事务管理,事务管理器即一个通知类, 我们为该通知类设置切点为service层方法即可完成事务自动管理。 由于不同技术操作数据库,进行事务操作的方法不同。如:JDBC提 交事务是 connection.commit() ,MyBatis提交事务是 sqlSession.commit() ,所以 Spring提供了多个事务管理器。

 我们使用MyBatis操作数据库,接下来使用 DataSourceTransactionManager 进行事务管理。

 1、引入依赖



    org.springframework
    spring-tx
    5.3.13



    org.aspectj
    aspectjweaver
    1.8.7

2、在配置文件中引入约束

xmlns:aop="http://www.springframework.org/schema/aop"
xmlns:tx="http://www.springframework.org/schema/tx"
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop.xsd
http://www.springframework.org/schema/tx
http://www.springframework.org/schema/tx/spring-tx.xsd

3、进行事务配置



    



    
        
    



    
    
    
    

Spring事务_事务控制的API

 Spring进行事务控制的功能是由三个接口提供的,这三个接口是 Spring实现的,在开发中我们很少使用到,只需要了解他们的作用 即可:

PlatformTransactionManager接口

PlatformTransactionManager是Spring提供的事务管理器接口,所 有事务管理器都实现了该接口。该接口中提供了三个事务操作方法:

1、TransactionStatus getTransaction(TransactionDefinition definition):获取事务状态信息。

2、void commit(TransactionStatus status):事务提交

3、void rollback(TransactionStatus status):事务回滚

 TransactionDefinition接口

TransactionDefinition是事务的定义信息对象,它有如下方法:

String getName():获取事务对象名称。

int getIsolationLevel():获取事务的隔离级别。

int getPropagationBehavior():获取事务的传播行为。

int getTimeout():获取事务的超时时间。

boolean isReadOnly():获取事务是否只读。

TransactionStatus接口 

TransactionStatus是事务的状态接口,它描述了某一时间点上事务 的状态信息。它有如下方法:

void flush() 刷新事务

boolean hasSavepoint() 获取是否存在保存点

boolean isCompleted() 获取事务是否完成

boolean isNewTransaction() 获取是否是新事务

boolean isRollbackOnly() 获取是否回滚

void setRollbackOnly() 设置事务回滚

Spring事务_事务的相关配置 

中可以进行事务的相关配置:


    
        
        
    

 Spring事务_事务的传播行为

 事务传播行为是指多个含有事务的方法相互调用时,事务如何在这 些方法间传播。 如果在service层的方法中调用了其他的service方法,假设每次执行 service方法都要开启事务,此时就无法保证外层方法和内层方法处 于同一个事务当中。

// method1的所有方法在同一个事务中
public void method1(){
    // 此时会开启一个新事务,这就无法保证method1()中所有的代码是在同一个事务中
    method2();
    System.out.println("method1");
}
public void method2(){
    System.out.println("method2");
}

事务的传播特性就是解决这个问题的,Spring帮助我们将外层方法 和内层方法放入同一事务中。

Spring事务_事务的隔离级别 

 事务隔离级别反映事务提交并发访问时的处理态度,隔离级别越 高,数据出问题的可能性越低,但效率也会越低。

 Spring事务_注解配置声明式事务

Spring支持使用注解配置声明式事务。用法如下:

1、注册事务注解驱动


2、在需要事务支持的方法或类上加@Transactional

 @Service
// 作用于类上时,该类的所有public方法将都具有该类型的事务属性
@Transactional(propagation = Propagation.REQUIRED,isolation = Isolation.DEFAULT)
public class AccountService {
    @Autowired
    private AccountDao accountDao;
    /**
     * 转账
     * @param id1 转出人id
     * @param id2 转入人id
     * @param price 金额
     */
    // 作用于方法上时,该方法将都具有该类型的事务属性
    @Transactional(propagation = Propagation.REQUIRED,isolation = Isolation.DEFAULT)
    public void transfer(int id1, int id2,double price) {
        // account1修改余额
        Account account1 = accountDao.findById(id1);
        account1.setBalance(account1.getBalance()-price);
        accountDao.update(account1);
        int i = 1/0; // 模拟转账出错
        // account2修改余额
        Account account2 = accountDao.findById(id2);
        account2.setBalance(account2.getBalance()+price);
        accountDao.update(account2);
   }
}

3 配置类代替xml中的注解事务支持:在配置类上方写 @EnableTranscationManagement

@Configuration
@ComponentScan("com.tong")
@EnableTransactionManagement
public class SpringConfig {
    @Bean
    public DataSource getDataSource(){
        DruidDataSource druidDataSource = new DruidDataSource();
       druidDataSource.setDriverClassName("com.mysql.jdbc.Driver");
       druidDataSource.setUrl("jdbc:mysql:///spring");
       druidDataSource.setUsername("root");
       druidDataSource.setPassword("root");
        return druidDataSource;
}
    @Bean
    public SqlSessionFactoryBean getSqlSession(DataSource dataSource){
        SqlSessionFactoryBean sqlSessionFactoryBean = new SqlSessionFactoryBean();
        sqlSessionFactoryBean.setDataSource(dataSource);
        return sqlSessionFactoryBean;
   }
    @Bean
    public MapperScannerConfigurer getMapperScanner(){
        MapperScannerConfigurer mapperScannerConfigurer = new MapperScannerConfigurer();
        mapperScannerConfigurer.setBasePackage("com.tong.dao");
        return mapperScannerConfigurer;
   }
    @Bean
    public DataSourceTransactionManager getTransactionManager(DataSource dataSource){
         DataSourceTransactionManager dataSourceTransactionManager = new DataSourceTransactionManager();
      dataSourceTransactionManager.setDataSource(dataSource);
        return dataSourceTransactionManager;
   }
}

你可能感兴趣的:(Spring全家桶,#,Spring,spring,Spring事务)