视频讲解地址:(预留:待上传……)
让我们开始吧:
数据库事务是访问并可能修改数据库内容的单个逻辑工作单元。
让我们检查一下mysql数据库:
现在让我们将应用程序事务用于Spring Boot JDBC项目。
我们将开发一个用于员工管理的Spring Boot + JDBC项目。它将有3个服务
OrganizationService员工加入工作流程
OrganizationService员工退出工作流程
应用程序事务是应用程序操作的序列,被应用程序视为单个逻辑单元。对于我们的应用程序,joinOrganization方法将被视为一项完整的事务。 joinOrganization由两个动作组成-
最初,我们将不使用任何事务管理。默认情况下,spring boot事务是自动提交。但这不是一个好习惯,我们将在下一节中了解原因。
2、Pom文件的内容:
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.javainuse</groupId>
<artifactId>boot-jdbc</artifactId>
<version>0.0.1-SNAPSHOT</version>
<packaging>jar</packaging>
<name>boot-jdbc</name>
<description>Demo project for Spring Boot</description>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.1.1.RELEASE</version>
<relativePath /> <!-- lookup parent from repository -->
</parent>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
<java.version>1.8</java.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-jdbc</artifactId>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<scope>runtime</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
3、修改配置文件:(替换成自己的数据库服务器的ip,用户名和密码)
spring.datasource.url=jdbc:mysql://数据库服务器的ip/bootdb?createDatabaseIfNotExist=true&autoReconnect=true&useSSL=false
spring.datasource.username= 数据库用户名
spring.datasource.password= 密码
spring.datasource.platform=mysql
spring.datasource.initialization-mode=always
logging.level.org.springframework=DEBUG
4、这是初始化脚本,由Spring Boot JDBC-开始运行
DROP TABLE IF EXISTS employee;
DROP TABLE IF EXISTS employeeHealthInsurance;
CREATE TABLE employee (
empId VARCHAR(10) NOT NULL,
empName VARCHAR(100) NOT NULL
);
CREATE TABLE employeeHealthInsurance (
empId VARCHAR(10) NOT NULL,
healthInsuranceSchemeName VARCHAR(100) NOT NULL,
coverageAmount VARCHAR(100) NOT NULL
);
5、定义Model类Employee,它将代表Employee详细信息
package com.javainuse.model;
public class Employee {
private String empId;
private String empName;
public String getEmpId() {
return empId;
}
public void setEmpId(String empId) {
this.empId = empId;
}
public String getEmpName() {
return empName;
}
public void setEmpName(String empName) {
this.empName = empName;
}
@Override
public String toString() {
return "Employee [empId=" + empId + ", empName=" + empName + "]";
}
}
6、创建用于执行Employee操作的EmployeeDAO接口,如下所示:
package com.javainuse.dao;
import com.javainuse.model.Employee;
public interface EmployeeDao {
void insertEmployee(Employee cus);
void deleteEmployeeById(String empid);
}
7、创建实现EmployeeDAO接口的EmployeeDAOImpl,如下所示。
Spring Boot将在类路径和mysql上检测spring-jdbc,并将自动为我们创建一个数据源和一个JdbcTemplate。因为这样的基础结构现在可用,并且我们没有专用的配置,所以还将为我们创建一个DataSourceTransactionManager。
package com.javainuse.dao.impl;
import javax.annotation.PostConstruct;
import javax.sql.DataSource;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jdbc.core.support.JdbcDaoSupport;
import org.springframework.stereotype.Repository;
import com.javainuse.dao.EmployeeDao;
import com.javainuse.model.Employee;
@Repository
public class EmployeeDaoImpl extends JdbcDaoSupport implements EmployeeDao {
@Autowired
DataSource dataSource;
@PostConstruct
private void initialize() {
setDataSource(dataSource);
}
@Override
public void insertEmployee(Employee emp) {
String sql = "INSERT INTO employee " + "(empId, empName) VALUES (?, ?)";
getJdbcTemplate().update(sql, new Object[] { emp.getEmpId(), emp.getEmpName() });
}
@Override
public void deleteEmployeeById(String empid) {
String sql = "DELETE FROM employee WHERE empId = ?";
getJdbcTemplate().update(sql, new Object[] { empid });
}
}
8、定义Model类EmployeeHealthInsurance,它将代表Employee Health Insurance详细信息-
package com.javainuse.model;
public class EmployeeHealthInsurance {
private String empId;
private String healthInsuranceSchemeName;
private int coverageAmount;
public String getEmpId() {
return empId;
}
public void setEmpId(String empId) {
this.empId = empId;
}
public String getHealthInsuranceSchemeName() {
return healthInsuranceSchemeName;
}
public void setHealthInsuranceSchemeName(String healthInsuranceSchemeName) {
this.healthInsuranceSchemeName = healthInsuranceSchemeName;
}
public int getCoverageAmount() {
return coverageAmount;
}
public void setCoverageAmount(int coverageAmount) {
this.coverageAmount = coverageAmount;
}
}
9、创建执行以下医疗保险业务的HealthInsuranceDao-
package com.javainuse.dao;
import com.javainuse.model.EmployeeHealthInsurance;
public interface HealthInsuranceDao {
void registerEmployeeHealthInsurance(EmployeeHealthInsurance employeeHealthInsurance);
void deleteEmployeeHealthInsuranceById(String empid);
}
10、创建实现HealthInsuranceDao的EmployeeHealthInsuranceDAOImpl,如下所示:
package com.javainuse.dao.impl;
import javax.annotation.PostConstruct;
import javax.sql.DataSource;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jdbc.core.support.JdbcDaoSupport;
import org.springframework.stereotype.Repository;
import com.javainuse.dao.HealthInsuranceDao;
import com.javainuse.model.EmployeeHealthInsurance;
@Repository
public class HealthInsuranceDaoImpl extends JdbcDaoSupport implements HealthInsuranceDao {
@Autowired
DataSource dataSource;
@PostConstruct
private void initialize() {
setDataSource(dataSource);
}
@Override
public void registerEmployeeHealthInsurance(EmployeeHealthInsurance emp) {
String sql = "INSERT INTO employeeHealthInsurance "
+ "(empId, healthInsuranceSchemeName, coverageAmount) VALUES (?, ?,?)";
getJdbcTemplate().update(sql,
new Object[] { emp.getEmpId(), emp.getHealthInsuranceSchemeName(), emp.getCoverageAmount() });
}
@Override
public void deleteEmployeeHealthInsuranceById(String empid) {
String sql = "DELETE FROM employeeHealthInsurance WHERE empId = ?";
getJdbcTemplate().update(sql, new Object[] { empid });
}
}
11、创建用于执行员工操作的EmployeeService接口,如下所示:
package com.javainuse.service;
import com.javainuse.model.Employee;
public interface EmployeeService {
void insertEmployee(Employee emp);
void deleteEmployeeById(String empid);
}
12、创建实现EmployeeService的EmployeeServiceImpl,如下所示:
package com.javainuse.service.impl;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import com.javainuse.dao.EmployeeDao;
import com.javainuse.model.Employee;
import com.javainuse.service.EmployeeService;
@Service
public class EmployeeServiceImpl implements EmployeeService {
@Autowired
EmployeeDao employeeDao;
@Override
public void insertEmployee(Employee employee) {
employeeDao.insertEmployee(employee);
}
@Override
public void deleteEmployeeById(String empid) {
employeeDao.deleteEmployeeById(empid);
}
}
13、创建HealthInsuranceService接口,如下所示:
package com.javainuse.service;
import com.javainuse.model.EmployeeHealthInsurance;
public interface HealthInsuranceService {
void registerEmployeeHealthInsurance(EmployeeHealthInsurance employeeHealthInsurance);
void deleteEmployeeHealthInsuranceById(String empid);
}
14、创建HealthInsuranceServiceImpl,以实现HealthInsuranceService,如下所示:
package com.javainuse.service.impl;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import com.javainuse.dao.HealthInsuranceDao;
import com.javainuse.model.EmployeeHealthInsurance;
import com.javainuse.service.HealthInsuranceService;
@Service
public class HealthInsuranceServiceImpl implements HealthInsuranceService {
@Autowired
HealthInsuranceDao healthInsuranceDao;
@Override
public void registerEmployeeHealthInsurance(EmployeeHealthInsurance employeeHealthInsurance) {
healthInsuranceDao.registerEmployeeHealthInsurance(employeeHealthInsurance);
}
@Override
public void deleteEmployeeHealthInsuranceById(String empid) {
healthInsuranceDao.deleteEmployeeHealthInsuranceById(empid);
}
}
15、创建OrganisationService接口,如下所示:
package com.javainuse.service;
import com.javainuse.model.Employee;
import com.javainuse.model.EmployeeHealthInsurance;
public interface OrganizationService {
public void joinOrganization(Employee employee, EmployeeHealthInsurance employeeHealthInsurance);
public void leaveOrganization(Employee employee, EmployeeHealthInsurance employeeHealthInsurance);
}
16、创建实现OrganizationService的OrganizationServiceImpl。它利用了EmployeeService和HealthInsuranceService。
package com.javainuse.service.impl;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import com.javainuse.model.Employee;
import com.javainuse.model.EmployeeHealthInsurance;
import com.javainuse.service.EmployeeService;
import com.javainuse.service.HealthInsuranceService;
import com.javainuse.service.OrganizationService;
@Service
public class OrganzationServiceImpl implements OrganizationService {
@Autowired
EmployeeService employeeService;
@Autowired
HealthInsuranceService healthInsuranceService;
@Override
public void joinOrganization(Employee employee, EmployeeHealthInsurance employeeHealthInsurance) {
employeeService.insertEmployee(employee);
healthInsuranceService.registerEmployeeHealthInsurance(employeeHealthInsurance);
}
@Override
public void leaveOrganization(Employee employee, EmployeeHealthInsurance employeeHealthInsurance) {
employeeService.deleteEmployeeById(employee.getEmpId());
healthInsuranceService.deleteEmployeeHealthInsuranceById(employeeHealthInsurance.getEmpId());
}
}
17、最后,如下创建Spring Boot Main类:
package com.javainuse;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.ApplicationContext;
import com.javainuse.model.Employee;
import com.javainuse.model.EmployeeHealthInsurance;
import com.javainuse.service.OrganizationService;
@SpringBootApplication
public class SpringBootJdbcApplication {
public static void main(String[] args) {
ApplicationContext context = SpringApplication.run(SpringBootJdbcApplication.class, args);
OrganizationService organizationService = context.getBean(OrganizationService.class);
Employee emp = new Employee();
emp.setEmpId("emp1");
emp.setEmpName("emp1");
EmployeeHealthInsurance employeeHealthInsurance = new EmployeeHealthInsurance();
employeeHealthInsurance.setEmpId("emp1");
employeeHealthInsurance.setHealthInsuranceSchemeName("premium");
employeeHealthInsurance.setCoverageAmount(20000);
organizationService.joinOrganization(emp, employeeHealthInsurance);
}
}
18、运行本工程:
如果现在运行该应用程序,则记录将被插入到employee表和employeehealthinsurance表中
假设employeeService调用成功,但是由于某种原因,healthInsuranceService调用失败。在这种情况下会发生什么。在这种情况下,还应该还原在employee表中为新雇员创建的条目。
让我们看看我们的应用程序在这种情况下的行为。
进行第一个服务调用后,我们将手动引发未经检查的异常。
package com.javainuse.service.impl;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import com.javainuse.model.Employee;
import com.javainuse.model.EmployeeHealthInsurance;
import com.javainuse.service.EmployeeService;
import com.javainuse.service.HealthInsuranceService;
import com.javainuse.service.OrganizationService;
@Service
public class OrganzationServiceImpl implements OrganizationService {
@Autowired
EmployeeService employeeService;
@Autowired
HealthInsuranceService healthInsuranceService;
@Override
public void joinOrganization(Employee employee, EmployeeHealthInsurance employeeHealthInsurance) {
employeeService.insertEmployee(employee);
if (employee.getEmpId().equals("emp1")) {
throw new RuntimeException("thowing exception to test transaction rollback");
}
healthInsuranceService.registerEmployeeHealthInsurance(employeeHealthInsurance);
}
@Override
public void leaveOrganization(Employee employee, EmployeeHealthInsurance employeeHealthInsurance) {
employeeService.deleteEmployeeById(employee.getEmpId());
healthInsuranceService.deleteEmployeeHealthInsuranceById(employeeHealthInsurance.getEmpId());
}
}
现在让我们运行该应用程序。
我们可以看到在雇员表中有记录,但在雇员健康保险表中没有。
现在让我们实施事务管理。
我们将使用事务注解。事务是一个跨领域的问题,它是在Spring Boot中使用AOP实现的。
package com.javainuse.service.impl;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import com.javainuse.model.Employee;
import com.javainuse.model.EmployeeHealthInsurance;
import com.javainuse.service.EmployeeService;
import com.javainuse.service.HealthInsuranceService;
import com.javainuse.service.OrganizationService;
@Service
public class OrganzationServiceImpl implements OrganizationService {
@Autowired
EmployeeService employeeService;
@Autowired
HealthInsuranceService healthInsuranceService;
@Override
@Transactional
public void joinOrganization(Employee employee, EmployeeHealthInsurance employeeHealthInsurance) {
employeeService.insertEmployee(employee);
if (employee.getEmpId().equals("emp1")) {
throw new RuntimeException("thowing exception to test transaction rollback");
}
healthInsuranceService.registerEmployeeHealthInsurance(employeeHealthInsurance);
}
@Override
@Transactional
public void leaveOrganization(Employee employee, EmployeeHealthInsurance employeeHealthInsurance) {
employeeService.deleteEmployeeById(employee.getEmpId());
healthInsuranceService.deleteEmployeeHealthInsuranceById(employeeHealthInsurance.getEmpId());
}
}
Spring Boot 隐式为事务注释方法创建代理。因此,对于此类方法,代理就像包装程序一样,负责在方法调用开始时创建事务,并在方法执行后提交事务。
拦截@Transactional注释方法的组件,例如EmployeeService。现在让我们再次运行该应用程序。
如果现在检查雇员和雇员健康保险表,则两者都没有记录,因此我们的记录将得到正确回滚。
点击–下载
https://www.javainuse.com/spring/boot-transaction