Springboot 如何使用事务来操作一些业务

事务的介绍


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

原子性(Atomicity):  一个事务是一个不可分割的工作单位,事务中包括的诸多操作要么都做,要么都不做。
一致性(Consistency):事务必须使数据库从一个一致性状态变成另一个一致性状态
隔离性(Isolation):一个事务的执行不能被其他事务干扰,即一个事务内部的操作及使用的数据对并发的其他事务时隔离的,并发执行的各个事务之间不能互相干扰。
持久性(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尽量不在类的上方使用,因为这样会对类内的全部方法使用事务,如果对查询方法使用事务,就可能会影响效率


————————————————
版权声明:本文为CSDN博主「风在咆哮」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/qq_37054816/article/details/104332358

posted @ 2023-08-29 22:31  苹果芒  阅读(58)  评论(0编辑  收藏  举报