事务的介绍
事务具有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