1、pom.xml
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid-spring-boot-starter</artifactId>
</dependency>
<!-- mybatis-plus启动器 -->
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-boot-starter</artifactId>
<version>3.5.1</version>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</dependency>
<!-- atomikos实现跨库事务 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-jta-atomikos</artifactId>
</dependency>
</dependencies>
2、yml文件配置
server:
port: 5053
spring:
application:
name: atomikos-service
mysql:
datasource:
test1:
url: jdbc:mysql://localhost:3306/test1?useUnicode=true&characterEncoding=utf8&useSSL=false&serverTimezone=UTC
username: root
password: root
driver-class-name: com.mysql.cj.jdbc.Driver
minPoolSize: 5
maxPoolSize: 20
maxLifetime: 20000
borrowConnectionTimeout: 30000
loginTimeout: 30
maintenanceInterval: 60
maxIdleTime: 60
test2:
url: jdbc:mysql://localhost:3306/test2?useUnicode=true&characterEncoding=utf8&useSSL=false&serverTimezone=UTC
username: root
password: root
driver-class-name: com.mysql.cj.jdbc.Driver
minPoolSize: 5
maxPoolSize: 20
maxLifetime: 20000
borrowConnectionTimeout: 30000
loginTimeout: 30
maintenanceInterval: 60
maxIdleTime: 60
# 日志级别
logging:
level:
root: info
3、数据库
create database test1;
use test1;
create table employee(
id int primary key auto_increment,
emp_name varchar(20) not null
);
create database test2;
use test2;
create table department(
id int primary key auto_increment,
name varchar(20) not null
);
select * from test1.employee;
select * from test2.department;
4、配置类
package com.bilibili.config;
import lombok.Data;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.stereotype.Component;
@Data
@Component
@ConfigurationProperties(prefix = "mysql.datasource.test1")
public class DBProperties1 {
private String url;
private String username;
private String password;
private String driverClassName;
private int minPoolSize;
private int maxPoolSize;
private int maxLifetime;
private int borrowConnectionTimeout;
private int loginTimeout;
private int maintenanceInterval;
private int maxIdleTime;
private String testQuery;
}
package com.bilibili.config;
import com.atomikos.jdbc.AtomikosDataSourceBean;
import com.mysql.cj.jdbc.MysqlXADataSource;
import org.apache.ibatis.session.SqlSessionFactory;
import org.mybatis.spring.SqlSessionFactoryBean;
import org.mybatis.spring.SqlSessionTemplate;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import javax.sql.DataSource;
import java.sql.SQLException;
@Configuration
@MapperScan(basePackages = "com.bilibili.mapper1",sqlSessionFactoryRef = "test1SqlSessionFactory")
public class DBConfig1 {
@Autowired
private DBProperties1 dbProperties1;
@Bean(name = "test1DataSource")
public DataSource testDataSource() {
MysqlXADataSource mysqlXADataSource = new MysqlXADataSource();
mysqlXADataSource.setUrl(dbProperties1.getUrl());
mysqlXADataSource.setUser(dbProperties1.getUsername());
mysqlXADataSource.setPassword(dbProperties1.getPassword());
try {
mysqlXADataSource.setPinGlobalTxToPhysicalConnection(true);
} catch (SQLException e) {
throw new RuntimeException(e);
}
AtomikosDataSourceBean atomikosDataSourceBean = new AtomikosDataSourceBean();
atomikosDataSourceBean.setXaDataSource(mysqlXADataSource);
atomikosDataSourceBean.setUniqueResourceName("test1DataSource");
atomikosDataSourceBean.setMinPoolSize(dbProperties1.getMinPoolSize());
atomikosDataSourceBean.setMaxPoolSize(dbProperties1.getMaxPoolSize());
atomikosDataSourceBean.setBorrowConnectionTimeout(dbProperties1.getBorrowConnectionTimeout());
try {
atomikosDataSourceBean.setLoginTimeout(dbProperties1.getLoginTimeout());
} catch (SQLException e) {
throw new RuntimeException(e);
}
atomikosDataSourceBean.setMaintenanceInterval(dbProperties1.getMaintenanceInterval());
atomikosDataSourceBean.setMaxIdleTime(dbProperties1.getMaxIdleTime());
atomikosDataSourceBean.setTestQuery(dbProperties1.getTestQuery());
return atomikosDataSourceBean;
}
@Bean(name = "test1SqlSessionFactory")
public SqlSessionFactory test1SessionFactory(@Qualifier("test1DataSource") DataSource dataSource) throws Exception {
SqlSessionFactoryBean sqlSessionFactoryBean = new SqlSessionFactoryBean();
sqlSessionFactoryBean.setDataSource(dataSource);
return sqlSessionFactoryBean.getObject();
}
@Bean(name = "test1SqlSessionTemplate")
public SqlSessionTemplate test1SqlSessionTemplate(@Qualifier("test1SqlSessionFactory") SqlSessionFactory sqlSessionFactory) {
return new SqlSessionTemplate(sqlSessionFactory);
}
}
package com.bilibili.config;
import lombok.Data;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.stereotype.Component;
@Data
@Component
@ConfigurationProperties(prefix = "mysql.datasource.test2")
public class DBProperties2 {
private String url;
private String username;
private String password;
private String driverClassName;
private int minPoolSize;
private int maxPoolSize;
private int borrowConnectionTimeout;
private int loginTimeout;
private int maintenanceInterval;
private int maxIdleTime;
private String testQuery;
}
package com.bilibili.config;
import com.atomikos.jdbc.AtomikosDataSourceBean;
import com.mysql.cj.jdbc.MysqlXADataSource;
import org.apache.ibatis.session.SqlSessionFactory;
import org.mybatis.spring.SqlSessionFactoryBean;
import org.mybatis.spring.SqlSessionTemplate;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import javax.sql.DataSource;
import java.sql.SQLException;
@Configuration
@MapperScan(basePackages = "com.bilibili.mapper2",sqlSessionFactoryRef = "test2SqlSessionFactory")
public class DBConfig2 {
@Autowired
private DBProperties2 dbProperties2;
@Bean(name = "test2DataSource")
public DataSource testDataSource() {
MysqlXADataSource mysqlXADataSource = new MysqlXADataSource();
mysqlXADataSource.setUrl(dbProperties2.getUrl());
mysqlXADataSource.setUser(dbProperties2.getUsername());
mysqlXADataSource.setPassword(dbProperties2.getPassword());
try {
mysqlXADataSource.setPinGlobalTxToPhysicalConnection(true);
} catch (SQLException e) {
throw new RuntimeException(e);
}
AtomikosDataSourceBean atomikosDataSourceBean = new AtomikosDataSourceBean();
atomikosDataSourceBean.setXaDataSource(mysqlXADataSource);
atomikosDataSourceBean.setUniqueResourceName("test2DataSource");
atomikosDataSourceBean.setMinPoolSize(dbProperties2.getMinPoolSize());
atomikosDataSourceBean.setMaxPoolSize(dbProperties2.getMaxPoolSize());
atomikosDataSourceBean.setBorrowConnectionTimeout(dbProperties2.getBorrowConnectionTimeout());
try {
atomikosDataSourceBean.setLoginTimeout(dbProperties2.getLoginTimeout());
} catch (SQLException e) {
throw new RuntimeException(e);
}
atomikosDataSourceBean.setMaintenanceInterval(dbProperties2.getMaintenanceInterval());
atomikosDataSourceBean.setMaxIdleTime(dbProperties2.getMaxIdleTime());
atomikosDataSourceBean.setTestQuery(dbProperties2.getTestQuery());
return atomikosDataSourceBean;
}
@Bean(name = "test2SqlSessionFactory")
public SqlSessionFactory test2SessionFactory(@Qualifier("test2DataSource") DataSource dataSource) throws Exception {
SqlSessionFactoryBean sqlSessionFactoryBean = new SqlSessionFactoryBean();
sqlSessionFactoryBean.setDataSource(dataSource);
return sqlSessionFactoryBean.getObject();
}
@Bean(name = "test2SqlSessionTemplate")
public SqlSessionTemplate testSqlSessionTemplate(@Qualifier("test2SqlSessionFactory") SqlSessionFactory sqlSessionFactory) {
return new SqlSessionTemplate(sqlSessionFactory);
}
}
5、实体类
package com.bilibili.entity1;
import lombok.Data;
@Data
public class Employee {
private Integer id;
private String empName;
}
package com.bilibili.entity2;
import lombok.Data;
@Data
public class Department {
private Integer id;
private String name;
}
6、Mapper 接口
package com.bilibili.mapper1;
import com.bilibili.entity1.Employee;
import org.apache.ibatis.annotations.Insert;
public interface EmployeeMapper {
@Insert("insert into employee(emp_name) values(#{empName})")
int insertEmp(Employee employee);
}
package com.bilibili.mapper2;
import com.bilibili.entity2.Department;
import org.apache.ibatis.annotations.Insert;
public interface DepartmentMapper {
@Insert("insert into department(name) values(#{name})")
int insertDept(Department department);
}
7、业务类
package com.bilibili.service;
public interface TestService {
void test();
}
package com.bilibili.service.impl;
import com.bilibili.entity1.Employee;
import com.bilibili.entity2.Department;
import com.bilibili.mapper1.EmployeeMapper;
import com.bilibili.mapper2.DepartmentMapper;
import com.bilibili.service.TestService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import javax.transaction.TransactionManager;
import javax.transaction.Transactional;
@Slf4j
@Service
public class TestServiceImpl implements TestService {
@Autowired
private TransactionManager transationManager;
@Autowired
private EmployeeMapper employeeMapper;
@Autowired
private DepartmentMapper departmentMapper;
@Transactional(rollbackOn = Exception.class)
@Override
public void test() {
// JtaTransactionManager jtaTransactionManager = (JtaTransactionManager) transationManager;
// UserTransaction userTransaction = jtaTransactionManager.getUserTransaction();
// log.info("===============userTransaction:{}", userTransaction);
Employee employee = new Employee();
employee.setEmpName("tom");
Department department = new Department();
department.setName("deptName");
employeeMapper.insertEmp(employee);
departmentMapper.insertDept(department);
// int i = 1 / 0;
}
}
8、启动类
@SpringBootApplication(scanBasePackages = {"com.bilibili"})
public class AtomikosApplication {
public static void main(String[] args) {
SpringApplication.run(AtomikosApplication.class, args);
}
}