SpringBoot中事务的使用

本文深入探讨事务的ACID特性:原子性、一致性、隔离性和持久性,并通过实例讲解如何在Spring框架中使用事务,包括实体类定义、控制器方法、事务注解的使用及事务的隔离级别和传播行为。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

事务的介绍

事务具有4个特性:原子性、一致性、隔离性、持久性。通常称为ACID特性。

  1. 原子性(Atomicity):一个事务是一个不可分割的工作单位,事务中包括的诸多操作要么都做,要么都不做。
  2. 一致性(Consistency):事务必须使数据库从一个一致性状态变成另一个一致性状态
  3. 隔离性(Isolation):一个事务的执行不能被其他事务干扰,即一个事务内部的操作及使用的数据对并发的其他事务时隔离的,并发执行的各个事务之间不能互相干扰。
  4. 持久性(Durability):一个事务一旦提交,他数据库中数据的改变就应该是永久性的,接下来的其他操作或故障不应该对其有任何影响

使用事务

实体类:

package com.example.chapter10_5.entity;

import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;

@Entity
public class Book {
	@Id
	@GeneratedValue(strategy = GenerationType.IDENTITY)
	private Long id;
	@Column(nullable = false,unique = true,length = 10)
	private String bookName;
	public Long getId() {
		return id;
	}
	public void setId(Long id) {
		this.id = id;
	}
	public String getBookName() {
		return bookName;
	}
	public void setBookName(String bookName) {
		this.bookName = bookName;
	}
	public Book(Long id, String bookName) {
		super();
		this.id = id;
		this.bookName = bookName;
	}
	public Book() {
		super();
		// TODO Auto-generated constructor stub
	}
	@Override
	public String toString() {
		return "Book [id=" + id + ", bookName=" + bookName + "]";
	}
	
}
package com.example.chapter10_5.repository;

import org.springframework.data.jpa.repository.JpaRepository;

import com.example.chapter10_5.entity.Book;

public interface BookRepository extends JpaRepository<Book, Long> {

}
package com.example.chapter10_5.controller;

import javax.transaction.Transactional;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;

import com.example.chapter10_5.entity.Book;
import com.example.chapter10_5.repository.BookRepository;
@RestController
public class BookController {
	@Autowired
	private BookRepository bookRepository;
	@GetMapping("/test1")
	public String test1() {
		 bookRepository.save(new Book(2l,"JAVA从入门到精通"));
	     bookRepository.save(new Book(3l,"SpringBoot2实战之旅"));
	     return "success";
	}
	
	@GetMapping("/test2")
	@Transactional
	public String test2() {
		 bookRepository.save(new Book(4l,"JAVA从入门到精通"));
	     bookRepository.save(new Book(5l,"SpringBoot2实战之旅"));
	     return "success";
	}
}
package com.example.chapter10_5.main;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.autoconfigure.domain.EntityScan;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.data.jpa.repository.config.EnableJpaRepositories;

@SpringBootApplication
@EntityScan(basePackages = {"com.example.chapter10_5.entity"})
@EnableJpaRepositories(basePackages = {"com.example.chapter10_5.repository"})
@ComponentScan(basePackages = {"com.example.chapter10_5.controller"})
public class Chapter115Application {

	public static void main(String[] args) {
		SpringApplication.run(Chapter115Application.class, args);
	}

}
spring.datasource.url=jdbc:mysql://localhost:3306/spring_boot_szzl?serverTimezone=UTC
spring.datasource.username=root
spring.datasource.password=root
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver

#create:没有表会创造表,原来表中的数据会清空
#create-drop:每次程序结束时会清空表
#update:每次运行程序,没有表格会新建表,表中的数据不会清空,只会更新
#validate:程序运行会校验数据与数据库字段类型是否相同,不同会报错
spring.jpa.hibernate.ddl-auto=update

spring.jpa.show-sql=true

启动项目,分别请求两个方法,test1方法由于没有事务的原因,第一条数据会插入成功,第二条数据会插入失败,这个插入的第一条数据就是脏数据;test2方法由于加入事务的原因,两条数据都不会插入成功,显然test2方法的场景更符合事务的特性。

Spring事务扩展介绍

spring事务不仅可以通过使用事务注解@Transactional,同时支持编程式使用事务,但是这种模式不常用。

事务的隔离级别

使用事务其实重用到了一个注解@Transactional,这就是Spring的注解式事务。事务隔离级别是指若干个事务并发时的隔离程度,Spring声明事务看可以通过isolation属性来设置Spring的事务隔离级别。

  • @Transactional(isolation = Isolation.DEFAULT):默认的隔离级别,及使用数据库的事务隔离级别
  • @Transactional(isolation = Isolation.READ_UNCOMMITTED):读未提交,最低的事务隔离级别,允许其他事务读取未提交的数据,这种级别的事务隔离会产生脏读,不可重复读和幻读。
  • @Transactional(isolation = Isolation.READ_COMMITTED):读已提交,能读取其他事务已提交的数据,不能读取未提交的数据,会产生不可重复读和幻读。
  • @Transactional(isolation = Isolation.REPEATABLE_READ):可重复读,可以防止不可重复读和脏读,但是会发生幻读。
  • @Transactional(isolation = Isolation.SERIALIZABLE):串行化,最高级别的事务隔离,会避免脏读,不可重复读和幻读。在这种隔离级别下,事务会按顺序进行。

事务传播行为

  • Propagation.REQUIRED:如果当前存在事务,就加入该事务;如果当前没有事务,就创建一个新的事务,这是spring默认的事务传播行为
  • Propagation.REQUIRES_NEW:创建一个新事务,如果当前存在事务,就把当前事务挂起。新建事务和被挂起的事务没有任何关系,是两个独立的事务。外层事务回滚失败时,不能回滚内层事务执行结果,内外层事务不能相互干扰。
  • Propagation.SUPPORTS:如果当前存在事务,就加入该事务;如果当前没有事务,就以非事务的方式继续运行。
  • Propagation.NOT_SUPPORTED:以非事务方式运行,如果当前存在事务,就把当前事务挂起。
  • Propagation.NEVER:以非事务方式运行,如果当前存在事务,就抛出异常
  • Propagation.MANDATORY:如果当前存在事务,就加入该事务;如果当前没有事务,就抛出异常
  • Propagation.NESTED:如果当前存在事务,就创建一个事务作为当前事务的嵌套事务来运行;如果当前没有事务,该取值就等价于Propagation.REQUIRED

声明式事务属性

Spring事务不只拥有事务隔离级别和事务传播行为,另外还包含很多属性。

  • value:存放String类型的值,主要用来指定不同的事务管理器,满足在同一个系统中存在不同事务管理器。比如在Spring容器中声明了多种事务管理器,然后开发者可以根据设置指定需要使用的事务管理器,通常一个系统需要访问多个数据库的场景下,就会设置对个事务管理器,然后进行不同的选择
  • transactionManager:与value类似,也是用来选择事务管理器。
  • propagation:事务传播行为,默认值是Propagation.REQUIRED
  • isolation:事务隔离级别,默认值是 Isolation.DEFAULT
  • timeout:超时时间,默认值是-1,如果超过了设置的时间还没有执行完成,就会自动回滚当前事务
  • readOnly:当前事务是不是只读事务,默认是false。通常可以设置读取数据的事务的属性值为true
  • rollbackFor:可以设置触发事务的指定异常,允许指定多个类型的异常。
  • noRollbackFor:与rollbackFor相反,可以设置不触发事务的指定异常,允许指定多个类型的异常

事务回滚规则

Spring的事务回滚通常是根据当前事务抛出异常的时候,Spring事务管理器捕捉到未经处理异常,然后根据规则来决定当前事务是否回滚。如果捕获的异常正好是设置notRollbackFor属性的异常,那么将不会被捕获。在默认配置下,Spring只有捕获运行时异常的子类时才会回滚。

@Transactional使用注意事项

  • @Transactional需要在类的上方使用,而不是在接口的上方使用,如果在接口上方使用,事务就会失效
  • @Transactional只能在public修饰的方法上,如果使用在private或protected修饰的方法上,事务就会无效
  • @Transactional尽量不在类的上方使用,因为这样会对类内的全部方法使用事务,如果对查询方法使用事务,就可能会影响效率
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值