0.实体类
package com.example.jta.entity.db1;
import lombok.Data;
import javax.persistence.*;
@Entity
@Table(name = "goods")
@Data
public class Goods {
@Id
@GeneratedValue(strategy= GenerationType.IDENTITY)
private Long id;
private String name;
}
package com.example.jta.entity.db2;
import lombok.Data;
import lombok.ToString;
import javax.persistence.*;
import java.io.Serializable;
import java.util.Date;
@Entity
@Table(name = "user")
@Data
@ToString
public class User implements Serializable {
@Id
@GeneratedValue(strategy= GenerationType.IDENTITY)
private Long id;
@Column
private String username;
@Column
private Date birthday;
@Column
private String sex;
@Column
private String address;
}
布局图
1.引入依赖
<?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>2.2.6.RELEASE</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>com.example</groupId>
<artifactId>jta-atomikos</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>jta-atomikos</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</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-jta-atomikos</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<!--版本不能太高-->
<version>8.0.11</version>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid</artifactId>
<version>1.1.12</version>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
2.Yaml配置
spring:
datasource:
db1:
driver-class-name: com.mysql.cj.jdbc.Driver
jdbc-url: jdbc:mysql://localhost:3306/db1?characterEncoding=utf-8&useSSL=false&serverTimezone=UTC
username: root
password: root
db2:
driver-class-name: com.mysql.cj.jdbc.Driver
jdbc-url: jdbc:mysql://localhost:3306/db2?characterEncoding=utf-8&useSSL=false&serverTimezone=UTC
username: root
password: root
jpa:
database: mysql
show-sql: true
database-platform: org.hibernate.dialect.MySQL57Dialect
#对于多数据源必须要这样设置,否则会报错
properties:
hibernate.hbm2ddl.auto: update
server:
port: 10010
3.数据源配置
package com.example.jta.config;
import com.alibaba.druid.pool.xa.DruidXADataSource;
import com.atomikos.jdbc.AtomikosDataSourceBean;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.autoconfigure.orm.jpa.JpaProperties;
import org.springframework.boot.orm.jpa.EntityManagerFactoryBuilder;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Primary;
import org.springframework.data.jpa.repository.config.EnableJpaRepositories;
import org.springframework.orm.jpa.JpaTransactionManager;
import org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean;
import org.springframework.transaction.PlatformTransactionManager;
import javax.annotation.Resource;
import javax.sql.DataSource;
import java.util.Objects;
/**
* 商品数据源配置
*/
@Configuration
@EnableJpaRepositories(basePackages = {"com.example.jta.dao.db1"}, entityManagerFactoryRef = "goodsEntityManagerFactory", transactionManagerRef = "goodsTransactionManager")
public class GoodsDataSourceConfig {
@Resource
private JpaProperties jpaProperties;
@Value("${spring.datasource.db1.jdbc-url}")
private String jdbcUrl;
@Value("${spring.datasource.db1.username}")
private String username;
@Value("${spring.datasource.db1.password}")
private String password;
/**
* 第一个数据源
*/
@Primary
@Bean(name = "goodsDataSource")
public DataSource goodsDataSource() {
DruidXADataSource druidXADataSource = new DruidXADataSource();
druidXADataSource.setUrl(jdbcUrl);
druidXADataSource.setUsername(username);
druidXADataSource.setPassword(password);
druidXADataSource.setDefaultAutoCommit(false);
AtomikosDataSourceBean atomikosDataSourceBean = new AtomikosDataSourceBean();
atomikosDataSourceBean.setXaDataSource(druidXADataSource);
atomikosDataSourceBean.setUniqueResourceName("goodsDataSource");
atomikosDataSourceBean.setPoolSize(5);
return atomikosDataSourceBean;
}
/**
* 商品实体类管理工厂
*/
@Primary
@Bean(name = "goodsEntityManagerFactory")
public LocalContainerEntityManagerFactoryBean goodsEntityManagerFactory(EntityManagerFactoryBuilder builder) {
return builder.dataSource(goodsDataSource())
.properties(jpaProperties.getProperties())
//设置实体类所在位置:类或包
.packages("com.example.jta.entity.db1")
//持久化单元名称
.persistenceUnit("goodsPersistenceUnit")
.build();
}
/**
* 商品事务管理器
*/
@Primary
@Bean(name = "goodsTransactionManager")
public PlatformTransactionManager goodsTransactionManager(EntityManagerFactoryBuilder builder) {
return new JpaTransactionManager(Objects.requireNonNull(goodsEntityManagerFactory(builder).getObject()));
}
}
package com.example.jta.config;
import com.alibaba.druid.pool.xa.DruidXADataSource;
import com.atomikos.jdbc.AtomikosDataSourceBean;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.autoconfigure.orm.jpa.JpaProperties;
import org.springframework.boot.orm.jpa.EntityManagerFactoryBuilder;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.jpa.repository.config.EnableJpaRepositories;
import org.springframework.orm.jpa.JpaTransactionManager;
import org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean;
import org.springframework.transaction.PlatformTransactionManager;
import javax.annotation.Resource;
import javax.sql.DataSource;
import java.util.Objects;
/**
* 用户数据源配置
*/
@Configuration
@EnableJpaRepositories(basePackages = {"com.example.jta.dao.db2"},entityManagerFactoryRef = "userEntityManagerFactory",transactionManagerRef = "userTransactionManager")
public class UserDataSourceConfig {
/**
* 自动注入jpa配置
*/
@Resource
private JpaProperties jpaProperties;
@Value("${spring.datasource.db2.jdbc-url}")
private String jdbcUrl;
@Value("${spring.datasource.db2.username}")
private String username;
@Value("${spring.datasource.db2.password}")
private String password;
@Bean(name = "userDataSource")
public DataSource userDataSource() {
DruidXADataSource druidXADataSource = new DruidXADataSource();
druidXADataSource.setUrl(jdbcUrl);
druidXADataSource.setUsername(username);
druidXADataSource.setPassword(password);
druidXADataSource.setDefaultAutoCommit(false);
AtomikosDataSourceBean atomikosDataSourceBean = new AtomikosDataSourceBean();
atomikosDataSourceBean.setXaDataSource(druidXADataSource);
atomikosDataSourceBean.setUniqueResourceName("userDataSource");
atomikosDataSourceBean.setPoolSize(5);
return atomikosDataSourceBean;
}
/**
* 将数据源、连接池、以及其他配置策略进行封装返回给事务管理器
* 自动装配时当出现多个Bean候选者时,被注解为@Primary的Bean将作为首选者,否则将抛出异常
*/
@Bean(name = "userEntityManagerFactory")
public LocalContainerEntityManagerFactoryBean userEntityManagerFactory(EntityManagerFactoryBuilder builder){
return builder.dataSource(userDataSource())
.properties(jpaProperties.getProperties())
//设置实体类所在位置:类或包
.packages("com.example.jta.entity.db2")
//持久化单元名称
.persistenceUnit("userPersistenceUnit")
.build();
}
/**
* 返回数据源的事务管理器
*/
@Bean(name = "userTransactionManager")
public PlatformTransactionManager userTransactionManager(EntityManagerFactoryBuilder builder){
return new JpaTransactionManager(Objects.requireNonNull(userEntityManagerFactory(builder).getObject()));
}
}
package com.example.jta.config;
import com.atomikos.icatch.jta.UserTransactionImp;
import com.atomikos.icatch.jta.UserTransactionManager;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Primary;
import org.springframework.transaction.jta.JtaTransactionManager;
import javax.transaction.UserTransaction;
/**
* 统一事务管理
*/
@Configuration
public class JtaTransactionManagerConfig {
@Primary
@Bean(name = "jtaTransactionManager")
public JtaTransactionManager regTransactionManager () {
UserTransactionManager userTransactionManager = new UserTransactionManager();
UserTransaction userTransaction = new UserTransactionImp();
return new JtaTransactionManager(userTransaction, userTransactionManager);
}
}
4.控制层Controller
package com.example.jta.controller;
import com.example.jta.entity.db1.Goods;
import com.example.jta.entity.db2.User;
import com.example.jta.service.GoodsService;
import com.example.jta.service.UserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.ResponseEntity;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
import java.util.Date;
@RestController
public class TransactionController {
@Autowired
private UserService userService;
@Autowired
private GoodsService goodsService;
@Transactional(value = "jtaTransactionManager", rollbackFor = Exception.class)
@GetMapping("/add")
public ResponseEntity addTest() {
Goods goods = new Goods();
goods.setId(1L);
goods.setName("涡轮发动机");
goodsService.addGoods(goods);
User user = new User();
user.setSex("男");
user.setUsername("周杰伦");
user.setAddress("上海");
user.setBirthday(new Date());
userService.addUser(user);
return ResponseEntity.ok("添加成功");
}
//在该接口中故意制造一个除零异常
@Transactional(value = "jtaTransactionManager", rollbackFor = Exception.class)
@GetMapping("/add2")
public ResponseEntity addTest2() {
Goods goods = new Goods();
goods.setId(2L);
goods.setName("兰博基尼");
goodsService.addGoods(goods);
User user = new User();
user.setSex("男");
user.setUsername("周润发");
user.setAddress("上海");
user.setBirthday(new Date());
userService.addUser(user);
int i = 10 / 0;
return ResponseEntity.ok("添加成功");
}
}
5.业务层Service
package com.example.jta.service;
import com.example.jta.entity.db1.Goods;
import java.util.List;
public interface GoodsService {
List<Goods> findAll();
Goods addGoods(Goods goods);
}
package com.example.jta.service;
import com.example.jta.entity.db2.User;
import java.util.List;
public interface UserService {
List<User> findAll();
User addUser(User user);
}
package com.example.jta.service.impl;
import com.example.jta.dao.db1.GoodsRepository;
import com.example.jta.entity.db1.Goods;
import com.example.jta.service.GoodsService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.transaction.interceptor.TransactionAspectSupport;
import java.util.List;
@Service
@Transactional(transactionManager = "goodsTransactionManager",rollbackFor = Exception.class,propagation = Propagation.NEVER)
public class GoodsServiceImpl implements GoodsService {
@Autowired
private GoodsRepository goodsRepository;
@Override
public List<Goods> findAll() {
return goodsRepository.findAll();
}
@Override
public Goods addGoods(Goods goods) {
try {
return goodsRepository.save(goods);
}catch (Exception e){
//强制手动事务回滚
TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
}
return null;
}
}
package com.example.jta.service.impl;
import com.example.jta.dao.db2.UserRepository;
import com.example.jta.entity.db2.User;
import com.example.jta.service.UserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.transaction.interceptor.TransactionAspectSupport;
import java.util.List;
@Service
@Transactional(transactionManager = "userTransactionManager", rollbackFor = Exception.class, propagation = Propagation.NEVER)
public class UserServiceImpl implements UserService {
@Autowired
private UserRepository userRepository;
@Override
public List<User> findAll() {
return userRepository.findAll();
}
@Override
public User addUser(User user) {
try {
return userRepository.save(user);
} catch (Exception e) {
//强制手动事务回滚
TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
}
return null;
}
}
6.数据层Dao
package com.example.jta.dao.db1;
import com.example.jta.entity.db1.Goods;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.JpaSpecificationExecutor;
import org.springframework.stereotype.Repository;
@Repository
public interface GoodsRepository extends JpaRepository<Goods, Long>, JpaSpecificationExecutor<Goods> {
}
package com.example.jta.dao.db2;
import com.example.jta.entity.db2.User;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.JpaSpecificationExecutor;
import org.springframework.stereotype.Repository;
@Repository
public interface UserRepository extends JpaRepository<User, Long>, JpaSpecificationExecutor<User> {
}
7.启动类
package com.example.jta;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration;
import org.springframework.boot.autoconfigure.jdbc.DataSourceTransactionManagerAutoConfiguration;
import org.springframework.transaction.annotation.EnableTransactionManagement;
@SpringBootApplication(exclude = {DataSourceAutoConfiguration.class, DataSourceTransactionManagerAutoConfiguration.class})
//手动进行事务管理
@EnableTransactionManagement
public class JtaAtomikosApplication {
public static void main(String[] args) {
SpringApplication.run(JtaAtomikosApplication.class, args);
}
}