Spring Boot声明式事务管理示例

Posted 独孤文彬

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Spring Boot声明式事务管理示例相关的知识,希望对你有一定的参考价值。

视频讲解地址:(预留:待上传……)
让我们开始吧:

什么是数据库事务?

数据库事务是访问并可能修改数据库内容的单个逻辑工作单元。

让我们检查一下mysql数据库:

  • mysql数据库打开两个单独的窗口
  • 在一个mysql窗口中,创建一个名为test的数据库,并在‘s其中创建一个名为employee的表
    create database test;
    create table employee(id varchar(10), name varchar(10));
  • 默认情况下,事务是针对mysql数据库自动提交的。 我们将使用以下命令禁用自动提交:
    SET autocommit = 0;
  • 在第一个mysql窗口中,使用以下插入命令-如果现在使用第二个mysql窗口,请对employee表进行选择,我们将看不到任何记录。这是因为事务仍未在第一个mysql窗口中提交。
  • 现在,我们在第一个MySQL命令中使用commit命令。如果现在使用第二个mysql窗口,请选择employee表,我们将看到两条记录

应用程序中的事务:

现在让我们将应用程序事务用于Spring Boot JDBC项目。
我们将开发一个用于员工管理的Spring Boot + JDBC项目。它将有3个服务

  • EmployeeService-服务将执行员工操作
  • HealthInsuranceService-该服务将执行员工健康保险业务
  • OrganizationService-服务将执行组织级别的操作,例如员工加入和退出。它利用EmployeeService和HealthInsuranceService

OrganizationService员工加入工作流程

OrganizationService员工退出工作流程


应用程序事务是应用程序操作的序列,被应用程序视为单个逻辑单元。对于我们的应用程序,joinOrganization方法将被视为一项完整的事务。 joinOrganization由两个动作组成-

  • 持久化员工信息
  • 持久化健康保险信息

    如果由于任何原因上述任何一个操作失败,则另一个操作也应回滚。因此,如果插入了“员工信息”,但假设由于某些原因而导致HealthInsurance失败,则还应该回滚“员工信息”。这意味着逻辑工作单元是全部或全部。 exitOrganization方法的情况与此类似,它将被视为一个工作单元。


最初,我们将不使用任何事务管理。默认情况下,spring boot事务是自动提交。但这不是一个好习惯,我们将在下一节中了解原因。

程序细节展示

1、工程结构

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以上是关于Spring Boot声明式事务管理示例的主要内容,如果未能解决你的问题,请参考以下文章

Spring Boot 揭秘与实战 数据存储篇 - 声明式事务管理

Spring Boot2 系列教程 | 实现声明式事务

Spring boot 入门五:springboot 开启声明式事务

Spring Boot事务管理-事务回滚示例

Spring Boot事务管理-事务回滚示例

Spring Boot 中使用 @Transactional 注解配置事务管理