SpringBoot之事务处理机制

非 Y 不嫁゛ 提交于 2019-11-30 22:55:30

一、Spring的事务机制

所有的数据访问技术都有事务处理机制,这些技术提供了API用来开启事务、提交事务来完成数据操作,或者在发生错误的时候回滚数据。

Spring的事务机制是用统一的机制来处理不同数据访问技术的事务处理。Spring的事务机制提供了一个PlatformTransactionManager接口,不同的数据访问技术的事务使用不同的接口实现:

 

在程序中定义事务管理器的代码如下:

@Bean

public PlatformTransactionManager transactionManager() {

 JpaTransactionManager transactionManager = new JpaTransactionManager();

 transactionManager.setDataSource(dataSource());

 return transactionManager;

}

二、声明式事务

Spring支持声明式事务,即使用注解来选择需要使用事务的方法,它使用@Transactional注解在方法上表明该方法需要事务支持。

@Transactional

public void saveSomething(Long id, String name) {

 //数据库操作

}

在此处需要特别注意的是,此@Transactional注解来自org.springframework.transaction.annotation包,而不是javax.transaction。

Spring提供了一个@EnableTransactionManagement注解在配置类上来开启声明式事务的支持。使用了@EnableTransactionManagement后,Spring容器会自动扫描注解@Transactional的方法和类。@EnableTransactionManagement的使用方式如下:

@Configuration

@EnableTransactionManagement

public class AppConfig {

}

三、类级别使用@Transactional

@Transactional不仅可以注解在方法上,也可以注解在类上。当注解在类上的时候意味着此类的所有public方法都是开启事务的。如果类级别和方法级别同时使用了@Transactional注解,则使用在类级别的注解会重载方法级别的注解。

四、Spring Data JPA的事务支持

Spring Data JPA对所有的默认方法都开启了事务支持,且查询类事务默认启用readOnly=true属性。

这个从源码SimpleJpaRepository中可以看出,SimpleJpaRepository在类级别定义了@Transactional(readOnly=true),而在和save、delete相关的操作重写了@Transactional属性,此时readOnly属性是false,其余查询操作readOnly仍然为false。

五、Spring Boot的事务支持

1.自动配置的事务管理器

在使用JDBC作为数据访问技术的时候,SpringBoot为我们定义了PlatformTransactionManager的实现DataSourceTransactionManager的Bean;配置见org.springframework.boot.autoconfigure.jdbc.DataSourceTransactionManagerAutoConfiguration类中的定义:

@Bean

@ConditionalOnMissingBean

@ConditionalOnBean(DataSource.class)

public PlatformTransactionManager transactionManager() {

 return new DataSourceTransactionManager(this.dataSource);

}

在使用JPA作为数据访问技术的时候,Spring Boot为我们了定义一个PlatformTransactionManager的实现JpaTransactionManager的Bean;配置见org.springframework.boot.autoconfigure.orm.jpa.JpaBaseConfiguration.class类中的定义:

@Bean

@ConditionalOnMissingBean(PlatformTransactionManager.class)

public PlatformTransactionManager transactionManager() {

 return new JpaTransactionManager();

}

2.自动开启注解事务的支持

Spring Boot专门用于配置事务的类为:org.springframework.boot.autoconfigure.transaction.TransactionAutoConfiguration,此配置类依赖于JpaBaseConfiguration和DataSourceTransactionManagerAutoConfiguration。

而在DataSourceTransactionManagerAutoConfiguration配置里还开启了对声明式事务的支持,代码如下:

@ConditionalOnMissingBean(AbstractTransactionManagementConfiguration.class)

@Configuration

@EnableTransactionManagement

protected static class TransactionManagementConfiguration {

}

所以在Spring Boot中,无须显示开启使用@EnableTransactionManagement注解。

六、实例(Springboot)

1.pom.xml:

<dependency>

 <groupId>org.springframework.boot</groupId>

 <artifactId>spring-boot-starter-web</artifactId>

</dependency>

<dependency>

 <groupId>org.springframework.boot</groupId>

 <artifactId>spring-boot-starter-data-jpa</artifactId>

</dependency>

<dependency>

 <groupId>org.springframework.boot</groupId>

<artifactId>spring-boot-starter-data-rest</artifactId>

</dependency>

<dependency>

 <groupId>mysql</groupId>

 <artifactId>mysql-connector-java</artifactId>

 <scope>runtime</scope>

</dependency>

  1. application.yml:

server:

 port: 5000  

spring:

 datasource:

 driver-class-name: com.mysql.jdbc.Driver

 url: jdbc:mysql://localhost:3306/test?useUnicode=true&characterEncoding=utf8&characterSetResults=utf8 

 username: root

 password: password

 jpa:

 hibernate:

 ddl-auto: update # 第一次简表create 后面用update

 show-sql: true

  1. 实体类Staff:

@Entity

public class Staff {

 @Id

 @GeneratedValue

 private Long id;

 private String name;

 private Integer age;

 private String address;

 public Staff() {

 super();

 }

 public Staff(Long id, String name, Integer age, String address) {

 super();

 this.id = id;

 this.name = name;

 this.age = age;

 this.address = address;

 }

 //省略get、set方法

}

  1. Staff的Repository:

public interface StaffRepository extends JpaRepository<Staff, Long> {

}

  1. 服务接口:

public interface StaffService {

 public Staff saveStaffWithRollBack(Staff staff);//回滚

 public Staff saveStaffWithoutRollBack(Staff staff);//不回滚

}

  1. 服务实现:

@Service

public class StaffServiceImpl implements StaffService {

 @Autowired

 StaffRepository staffRepository; //可以直接注入我们的RersonRepository的Bean。

 @Override

 //使用@Transactional注解的rollbackFor属性,指定特定异常时,数据回滚。

 @Transactional(rollbackFor = {IllegalArgumentException.class})

 public Staff saveStaffWithRollBack(Staff staff) {

 Staff s = staffRepository.save(staff);

 if (staff.getName().equals("张三")) {

  throw new IllegalArgumentException("张三已经存在了,rollback");

 }

 return s;

 }

  

 @Override

 public Staff saveStaffWithoutRollBack(Staff staff) {

 Staff s = staffRepository.save(staff);

 if (staff.getName().equals("张三")) {

  throw new IllegalArgumentException("张三已经存在了,数据不回滚");

 }

 return s;

 }

}

  1. Controller:

@RestController

@RequestMapping("/staff")

public class StaffController {

 @Autowired

 StaffService staffService;

 //测试回滚情况

 @RequestMapping("/rollback")

 public Staff rollback(Staff staff) {

 return staffService.saveStaffWithRollBack(staff);

 }

 //测试不回滚情况

 @RequestMapping("/notrollback")

 public Staff noRollBack(Staff staff) {

 return staffService.saveStaffWithoutRollBack(staff);

 }

}

8.运行测试:

1)回滚:http://localhost:5000/staff/rollback?name=张三&age=18

 

控制台:

 

数据库:

 

2)不回滚:http://localhost:5000/staff/notrollback?name=张三&age=18

 

控制台:

数据库:

 

 获取更多学习资料,可以扫码进群或关注公众号

 

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!