Spring分布式事物--链式事务的实现

1,662 阅读2分钟

一:创建一个新的SpringBoot项目,pom.xml文件如下

    <?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 https://maven.apache.org/xsd/maven-4.0.0.xsd">
        <modelVersion>4.0.0</modelVersion>
        <parent>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-parent</artifactId>
            <version>1.5.9.RELEASE</version>
            <relativePath/> <!-- lookup parent from repository -->
        </parent>
        <groupId>com.example</groupId>
        <artifactId>springboot_tx_chain</artifactId>
        <version>0.0.1-SNAPSHOT</version>
        <name>springboot_tx_chain</name>
        <description>Demo project for Spring Boot</description>

<properties>
    <java.version>1.8</java.version>
</properties>

<dependencies>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-web</artifactId>
    </dependency>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-jdbc</artifactId>
    </dependency>
    <dependency>
        <groupId>com.zaxxer</groupId>
        <artifactId>HikariCP</artifactId>
        <version>2.7.9</version>
    </dependency>
    <dependency>
        <groupId>mysql</groupId>
        <artifactId>mysql-connector-java</artifactId>
        <version>5.1.38</version>
    </dependency>
    <!-- https://mvnrepository.com/artifact/org.springframework.data/spring-data-commons -->
    <dependency>
        <groupId>org.springframework.data</groupId>
        <artifactId>spring-data-commons</artifactId>
        <version>1.13.7.RELEASE</version>
    </dependency>
</dependencies>
<build>
    <plugins>
        <plugin>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-maven-plugin</artifactId>
        </plugin>
    </plugins>
</build>

项目整体架构如下

application.properties文件如下,这里使用了二个数据库,模拟分布式环境

spring.ds_1.url=jdbc:mysql://localhost:3306/test01
spring.ds_1.username=root
spring.ds_1.password=root
spring.ds_1.driver-class-name=com.mysql.jdbc.Driver

spring.ds_2.url=jdbc:mysql://localhost:3306/test02
spring.ds_2.username=root
spring.ds_2.password=root
spring.ds_2.driver-class-name=com.mysql.jdbc.Driver

DBConfiguration.class类如下:

package com.config;

import com.zaxxer.hikari.HikariDataSource;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.boot.autoconfigure.jdbc.DataSourceProperties;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Primary;
import org.springframework.dao.support.ChainedPersistenceExceptionTranslator;
import org.springframework.data.transaction.ChainedTransactionManager;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.jdbc.datasource.DataSourceTransactionManager;
import org.springframework.transaction.PlatformTransactionManager;

import javax.sql.DataSource;

@Configuration
public class DBConfiguration {


@Bean
@Primary
@ConfigurationProperties(prefix = "spring.ds_1")
public DataSourceProperties user1DataSourceProperty() {
      return new DataSourceProperties();
}

@Bean
@Primary
public DataSource user1DataSource() {
    return user1DataSourceProperty().initializeDataSourceBuilder().type(HikariDataSource.class).build();
}

@Bean
public JdbcTemplate user1JdbcTemplate(@Qualifier("user1DataSource") DataSource dataSource) {
    return new JdbcTemplate(dataSource);
}


@Bean
@ConfigurationProperties(prefix = "spring.ds_2")
public DataSourceProperties user2DataSourceProperty() {
    return new DataSourceProperties();
}

@Bean
public DataSource user2DataSource() {
    return user2DataSourceProperty().initializeDataSourceBuilder().type(HikariDataSource.class).build();
}

@Bean
public JdbcTemplate user2JdbcTemplate(@Qualifier("user2DataSource") DataSource dataSource) {
    return new JdbcTemplate(dataSource);
}


@Bean
public PlatformTransactionManager transactionManager() {
    DataSourceTransactionManager user1TR = new DataSourceTransactionManager(user1DataSource());
    DataSourceTransactionManager user2TR = new DataSourceTransactionManager(user2DataSource());
    ChainedTransactionManager chainedTransactionManager = new ChainedTransactionManager(user1TR,user2TR);
    return chainedTransactionManager;
}

}

PeopleService.class:

package com.service;

import com.entity.People;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

@Service
public class PeopleService {

@Autowired
@Qualifier("user1JdbcTemplate")
private JdbcTemplate user1JdbcTemplate;

@Autowired
@Qualifier("user2JdbcTemplate")
private JdbcTemplate user2JdbcTemplate;

@Transactional
public void addPeople(People people) {
    user1JdbcTemplate.update("insert into people (name) values (?)",people.getName());
    user2JdbcTemplate.update("insert into people (name) values (?)",people.getName());
    //抛出异常,使事物回滚
    multiError();
}

public void multiError() {
    throw new RuntimeException("Error data");
}

}

People.class:

package com.entity;

public class People {

private int id;
private String name;

public People() {
}

public People(int id, String name) {
    this.id = id;
    this.name = name;
}

public int getId() {
    return id;
}

public void setId(int id) {
    this.id = id;
}

public String getName() {
    return name;
}

public void setName(String name) {
    this.name = name;
}

}

PeopleController.class:

import com.entity.People;
import com.service.PeopleService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
@RequestMapping("/people")
public class PeopleController {


@Autowired private PeopleService peopleService;

@GetMapping("/savePeople")
public String savePeople() {
    People people = new People();
    people.setName("admin_2");
    peopleService.addPeople(people);
    return "success";
}

}