一、简介
我们在前面已经分别介绍了如何在Spring Boot中使用JPA(初识在Spring Boot中使用JPA)以及如何在Spring Boot中输出REST资源( 在Spring Boot中输出REST资源)。那么关于数据库访问还有一个核心操作那就是事务的处理了,前面两篇博客小伙伴们已经见识到Spring Boot带给我们的巨大便利了,其实不用猜,我们也知道Spring Boot在数据库事务处理问题上也给我们带来惊喜,OK,废话不多说,就来看看如何在Spring Boot中使用事务吧。
二、创建项目
创建的时候选择依赖时选择Web、JPA和MySQL Driver,如下图:
工程创建好之后,添加 Druid 依赖,完整的依赖如下:
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid-spring-boot-starter</artifactId>
<version>1.1.10</version>
</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-web</artifactId>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
<exclusions>
<exclusion>
<groupId>org.junit.vintage</groupId>
<artifactId>junit-vintage-engine</artifactId>
</exclusion>
</exclusions>
</dependency>
在application.properties中数据库配置相关属性,配置方式还是和前文一模一样
spring.datasource.url=jdbc:mysql://localhost:3306/springboot?characterEncoding=utf8&useSSL=false&serverTimezone=Asia/Shanghai
spring.datasource.username=root
spring.datasource.password=123456
spring.datasource.type=com.alibaba.druid.pool.DruidDataSource
# JPA配置
spring.jpa.database=mysql
# 在控制台打印SQL
spring.jpa.show-sql=true
# 数据库平台
spring.jpa.database-platform=mysql
# 每次启动项目时,数据库初始化策略
spring.jpa.hibernate.ddl-auto=update
# 指定默认的存储引擎为InnoDB
spring.jpa.properties.hibernate.dialect=org.hibernate.dialect.MySQL57Dialect
创建实体类,还是和前文一模一样
package com.example.springboottest11.model;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
@Entity
public class Person {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private String name;
private Integer age;
private String address;
public Person() {
}
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Integer getAge() {
return age;
}
public void setAge(Integer age) {
this.age = age;
}
public String getAddress() {
return address;
}
public void setAddress(String address) {
this.address = address;
}
public Person(Long id, String name, Integer age, String address) {
this.id = id;
this.name = name;
this.age = age;
this.address = address;
}
}
创建实体类的Repository
package com.example.springboottest11.repository;
import com.example.springboottest11.model.Person;
import org.springframework.data.jpa.repository.JpaRepository;
public interface PersonRepository extends JpaRepository<Person, Long> {
}
这里因为我们的目的是测试事务,所以Repository中暂时先不写任何东西。
创建Service接口
package com.example.springboottest11.service;
import com.example.springboottest11.model.Person;
public interface DemoService {
public Person savePersonWithRollBack(Person person);
public Person savePersonWithoutRollBack(Person person);
}
创建Service实现类
package com.example.springboottest11.service.impl;
import com.example.springboottest11.model.Person;
import com.example.springboottest11.repository.PersonRepository;
import com.example.springboottest11.service.DemoService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
@Service
public class DemoServiceImpl implements DemoService {
@Autowired
private PersonRepository personRepository;
@Transactional(rollbackFor = {IllegalArgumentException.class})
@Override
public Person savePersonWithRollBack(Person person) {
Person p = personRepository.save(person);
if(person.getName().equals("sang")){
throw new IllegalArgumentException("sang已存在,数据将回滚");
}
return p;
}
@Transactional(noRollbackFor = {IllegalArgumentException.class})
@Override
public Person savePersonWithoutRollBack(Person person) {
Person p = personRepository.save(person);
if(person.getName().equals("sang")){
throw new IllegalArgumentException("sang已存在,但数据不会回滚");
}
return p;
}
}
在这里我们使用到了@Transactional注解,该注解中有一个rollbackFor属性,该属性的值为数组,表示当该方法中抛出指定的异常时数据回滚,该注解还有个属性叫noRollbackFor,表示当该方法中抛出指定的异常时数据不回滚,这两个属性我们分别在两个方法中体现。
创建控制器
package com.example.springboottest11.controller;
import com.example.springboottest11.model.Person;
import com.example.springboottest11.service.DemoService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
public class MyController {
@Autowired
private DemoService demoService;
@RequestMapping("/norollback")
public Person noRollback(Person person) {
return demoService.savePersonWithoutRollBack(person);
}
@RequestMapping("/rollback")
public Person rollback(Person person) {
return demoService.savePersonWithRollBack(person);
}
}
控制器创建成功之后接下来我们就可以直接在浏览器中访问这两个地址看看效果了。
三、测试
首先在浏览器中输入http://localhost:8080/rollback?name=sang&age=100
,我们来测试回滚的情况,访问结果如下:
这个时候再去查看数据库,发现数据表中并没有插入数据。
再在地址栏输入http://localhost:8080/norollback?name=sang&age=100
,测试结果如下:
浏览器依然报错:
但是这个时候再去看数据库,数据已成功插入了。
ps:mysql的MyISAM存储引擎不支持事务,本次项目使用的是InnoDB存储引擎。
OK,以上就是数据库事务在Spring Boot中的简单使用。
学习借鉴自https://blog.csdn.net/u012702547/article/details/54098190