一:创建一个新的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";
}
}