_Spring 事务的相关配置、传播行为、隔离级别及注解配置声明式事务

2023-11-19 22:50:12 浏览数 (1)

一、事务的相关配置

1. 添加测试标签

在 <tx:advice> 中可以进行事务的相关配置: <tx:method> 中的属性:

  1. name:指定配置的方法。 * 表示所有方法, find* 表示所有以find开头的方法。
  2. read-only:是否是只读事务,只读事务不存在数据的修改,数据库将会为只读事务提供一些
  3. 优化手段,会对性能有一定提升,建议在查询中开启只读事务。
  4. timeout:指定超时时间,在限定的时间内不能完成所有操作就会抛异常。默认永不超时
  5. rollback-for:指定某个异常事务回滚,其他异常不回滚。默认所有异常回滚。
  6. no-rollback-for:指定某个异常不回滚,其他异常回滚。默认所有异常回滚。
  7. propagation:事务的传播行为
  8. isolation:事务的隔离级别

添加 <tx:advice>标签

代码语言:javascript复制
    <!-- 进行事务相关配置 -->
    <tx:advice id = "txAdvice">
        <tx:attributes>
            <!-- 代表以find开头的方法 -->
            <tx:method name="find*" read-only="true"/>
        </tx:attributes>
    </tx:advice>

2. 添加对应方法

        这里我们对查找用户id的时候进行用户修改,看看测试的时候是否报异常,因为上面我们已经设置了find方法开头为只读事务,不能对数据进行修改 

代码语言:javascript复制
public Account findById(int id){
        Account account = accountDao.findById(1);
        account.setBalance(1000);
        accountDao.update(account);
        return accountDao.findById(id);
}

3. 测试

添加测试方法

代码语言:javascript复制
    @Test
    public void testFindById(){
        Account account = accountService.findById(1);
        System.out.println(account);
    }

测试结果

OK,因此我们可以看到确实以find开头的方法确实是只能读取,不能修改。 

二、事务的传播行为

        事务传播行为是指多个含有事务的方法相互调用时,事务如何在这些方法间传播。         如果在service层的方法中调用了其他的service方法,假设每次执行service方法都要开启事务,此时就无法保证外层方法和内层方法处于同一个事务当中。 例如: // method1的所有方法在同一个事务中 public void method1(){   // 此时会开启一个新事务,这就无法保证method1() 中所有的代码是在同一个事务中   method2();   System.out.println("method1"); } public void method2(){   System.out.println("method2"); }

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

传播行为

介绍

REQUIRED

默认。支持当前事务,如果当前没有事务,就新建一个事务。这是最常见的选择。

SUPPORTS

支持当前事务,如果当前没有事务,就以非事务方式执行。

MANDATORY

支持当前事务,如果当前没有事务,就抛出异常。

REQUIRES_NEW

新建事务,如果当前存在事务,把当前事务挂起。

NOT_SUPPORTED

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

NEVER

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

NESTED

必须在事务状态下执行,如果没有事务则新建事务,如果当前有事务则创建一个嵌套事务

三、事务的隔离级别

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

隔离级别

脏读

不可重复读

幻读

READ_UNCOMMITED(读取未提交内容)

Yes

Yes

Yes

READ_COMMITED(读取提交内容)

No

Yes

Yes

REPEATABLE_READ(重复读)

No

No

Yes

SERIALIZABLE(可串行化)

No

No

No

如果设置为DEFAULT会使用数据库的隔离级别。

  • SqlServer , Oracle默认的事务隔离级别是READ_COMMITED
  • Mysql的默认隔离级别是REPEATABLE_READ

四、注解配置声明式事务

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

1. 注册事务注解驱动

代码语言:javascript复制
<!-- 注册事务注解驱动 -->
<tx:annotation-driven transaction-manager="transactionManager">
</tx:annotation-driven>

2. 加上注解

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

代码语言:javascript复制
package com.example.service;

import com.example.dao.AccountDao;
import com.example.pojo.Account;
import org.mybatis.spring.SqlSessionTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Isolation;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.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 金额
     */
    // 作用方法上时,该方法都将具有该类型事务的事务属性
    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);
       
    }
}

3. 配置类代替xml文件中的注解事务支持

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

代码语言:javascript复制
import com.alibaba.druid.pool.DruidDataSource;
import org.mybatis.spring.SqlSessionFactoryBean;
import org.mybatis.spring.mapper.MapperScannerConfigurer;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.jdbc.datasource.DataSourceTransactionManager;
import org.springframework.transaction.annotation.EnableTransactionManagement;

import javax.sql.DataSource;

@Configuration
@ComponentScan("com.example")
@EnableTransactionManagement
public class SpringConfig {

    @Bean
    public DataSource getDataSource(){
        DruidDataSource druidDataSource = new DruidDataSource();

        druidDataSource.setDriverClassName("com.mysql.cj.jdbc.Driver");
        druidDataSource.setUrl("jdbc:mysql:///spring");
        druidDataSource.setUsername("root");
        druidDataSource.setPassword("666666");

        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.example.dao");

        return mapperScannerConfigurer;
    }

    @Bean
    public DataSourceTransactionManager getTransactionManger(DataSource dataSource){
        DataSourceTransactionManager dataSourceTransactionManager = new DataSourceTransactionManager();

        dataSourceTransactionManager.setDataSource(dataSource);

        return dataSourceTransactionManager;
    }
}

4. 测试

添加测试方法

代码语言:javascript复制
    // 测试注解配置类
    @Test
    public void testSpringConfig(){
        ApplicationContext ac = new AnnotationConfigApplicationContext(SpringConfig.class);
        AccountService service = (AccountService) ac.getBean("accountService");
        accountService.transfer(1,2,500);
    }

测试结果

        OK,可以看到确实出现异常中断了,因此测试成功,Spring专栏也到此告一段落啦 ,接下来就开启了SpringMVC框架学习。希望大家可以持续关注啊!!!

我正在参与2023腾讯技术创作特训营第三期有奖征文,组队打卡瓜分大奖!

0 人点赞