Spring tx

编程式事务与声明式事务

  1. 编程式事务

编程式事务是指手动编写程序来管理事务,即通过编写代码的方式直接控制事务的提交和回滚。在 Java 中,通常使用事务管理器(如 Spring 中的 PlatformTransactionManager)来实现编程式事务。

编程式事务的主要优点是灵活性高,可以按照自己的需求来控制事务的粒度、模式等等。但是,编写大量的事务控制代码容易出现问题,对代码的可读性和可维护性有一定影响。

编程式的实现方式存在缺陷:

  • 细节没有被屏蔽:具体操作过程中,所有细节都需要程序员自己来完成,比较繁琐。
  • 代码复用性不高:如果没有有效抽取出来,每次实现功能都需要自己编写代码,代码就没有得到复用。
  1. 声明式事务

声明式事务是指使用注解或 XML 配置的方式来控制事务的提交和回滚。

开发者只需要添加配置即可, 具体事务的实现由第三方框架实现,避免直接进行事务操作。

使用声明式事务可以将事务的控制和业务逻辑分离开来,提高代码的可读性和可维护性。

  1. Spring事务管理器

依赖:

  • spring-tx: 包含声明式事务实现的基本规范(事务管理器规范接口和事务增强等等)
  • spring-jdbc: 包含DataSource方式事务管理器实现类DataSourceTransactionManager
  • spring-orm: 包含其他持久层框架的事务管理器实现类例如:Hibernate/Jpa等

Spring声明式事务对应事务管理器接口:

img

使用案例

  1. 引入依赖
1
2
3
4
5
6
7
8
<dependencies>
  <!-- 声明式事务依赖-->
  <dependency>
      <groupId>org.springframework</groupId>
      <artifactId>spring-tx</artifactId>
      <version>6.0.6</version>
  </dependency>
</dependencies>
  1. 配置事务管理器
1
2
3
4
5
6
7
@Configuration
@ComponenScan("com.xxx")
@PropertySource(value = "classpath:jdbc.properties")
@EnableTransactionManagement //开启事务管理
public class DataSourceConfig {
	/*code*/
}
  1. 启用声明式注解@Transactional
1
2
3
4
5
6
7
8
9
@Service
public class StudentService {
    @Transactional
    public void changeInfo(){
        /*code1*/
        int i = 1/0;
        /*code2*/
    }
}
  1. 测试事务效果
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
@SpringJUnitConfig(classes = DataSourceConfig.class)
public class TxTest {
    @Autowired
    private StudentService studentService;

    @Test
    public void  testTx(){
        studentService.changeInfo();
    }
}

事务属性

  1. 只读
1
@Transactional(readOnly = true)

对一个方法来说,离它最近的 @Transactional 注解中的事务属性设置生效。因此方法上的注解可以覆盖类上的注解。对一个查询操作来说,如果我们把它设置成只读,就能够明确告诉数据库,这个操作不涉及写操作。这样数据库就能够针对查询操作来进行优化。

  1. 超时时间
1
2
//timeout设置事务超时时间,单位秒! 默认: -1 永不超时,不限制事务时间!
@Transactional(readOnly = false,timeout = 3)

超时回滚,释放资源。

  1. 事务异常
1
2
3
4
5
/*
rollbackFor = 指定哪些异常才会回滚,默认是 RuntimeException and Error 异常方可回滚!
noRollbackFor = 指定哪些异常不会回滚, 默认没有指定,如果指定,应该在rollbackFor的范围内!
*/
@Transactional(rollbackFor = Exception.class,noRollbackFor = FileNotFoundException.class)

默认只针对运行时异常回滚。

  1. 事务隔离级别
1
@Transactional(isolation = Isolation.REPEATABLE_READ)
  1. 读未提交(Read Uncommitted):事务可以读取未被提交的数据,容易产生脏读、不可重复读和幻读等问题。实现简单但不太安全,一般不用。

  2. 读已提交(Read Committed):事务只能读取已经提交的数据,可以避免脏读问题,但可能引发不可重复读和幻读。(Oracle默认隔离级别)。

  3. 可重复读(Repeatable Read):在一个事务中,相同的查询将返回相同的结果集,不管其他事务对数据做了什么修改。可以避免脏读和不可重复读,但仍有幻读的问题。(MySQL默认隔离级别)

  4. 串行化(Serializable):最高的隔离级别,完全禁止了并发,只允许一个事务执行完毕之后才能执行另一个事务。可以避免以上所有问题,但效率较低,不适用于高并发场景。

  5. 事务传播级别

1
@Transactional(propagation = Propagation.REQUIRES_NEW)
名称 含义
REQUIRED 默认值 如果父方法有事务,就加入,如果没有就新建自己独立事务。
REQUIRES_NEW 不管父方法是否有事务,都新建事务。
updatedupdated2023-10-312023-10-31