欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

详细介绍springboot整合多数据源和分布式事务管理

程序员文章站 2022-03-10 10:30:25
文章目录一、前话二、调用需要的依赖包三、配置数据源四、调用数据源五、编写持久层六、调用持久层七、启动项目一、前话最近开始一步一步的学习springboot框架,同时在这里分享学习笔记。开始之前先献上我的包结构,今天主要针对订单,会员两个部分调用各自的数据库,在springboot配置两个数据源。二、调用需要的依赖包



一、前话

最近开始一步一步的学习springboot框架,同时在这里分享学习笔记。今天主要针对订单,会员两个模块调用各自的数据库,在springboot配置两个数据源以及事务整合配置。

二、整合多数据源

首先献上我的包结构
详细介绍springboot整合多数据源和分布式事务管理

2.1调用需要的依赖包

<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.springboot</groupId>
	<artifactId>springboot-manyDatasource</artifactId>
	<version>0.0.1-SNAPSHOT</version>
	<parent>
		<groupId>org.springframework.boot</groupId>
		<artifactId>spring-boot-starter-parent</artifactId>
		<version>2.1.8.RELEASE</version>
	</parent>
	<dependencies>
		<!-- 对web开发的支持,包含了spring webmvc和tomcat等web开发的特性 -->
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-web</artifactId>
		</dependency>
		<dependency>
			<groupId>mysql</groupId>
			<artifactId>mysql-connector-java</artifactId>
			<version>5.1.21</version>
		</dependency>
		<dependency>
			<groupId>org.mybatis.spring.boot</groupId>
			<artifactId>mybatis-spring-boot-starter</artifactId>
			<version>1.1.1</version>
		</dependency>
	</dependencies>
	<build>
		<plugins>
			<plugin>
				<artifactId>maven-compiler-plugin</artifactId>
				<configuration>
					<source>1.8</source>
					<target>1.8</target>
				</configuration>
			</plugin>
		</plugins>
	</build>
</project> 

2.2配置数据源

之前我们配置文件都是用properties文件,后来发现yml文件的配置比较轻便,所以后面配置我都会使用yml文件。如果不懂yml和properties文件的区别,可以自行百度。这里在resource包下创建application.yml文件,配置如下。这里需要注意的是,在springboot2中有个bug,如果配置多数据源,数据库的地址需要写成 jdbc-url,如果写成url会出错!

spring:
   datasource:
    ###会员数据库
    member:
       jdbc-url: jdbc:mysql://localhost:3306/member
       username: root
       password: tiger
       driver-class-name: com.mysql.jdbc.Driver
       
    order:
       jdbc-url: jdbc:mysql://localhost:3306/order
       username: root
       password: tiger
       driver-class-name: com.mysql.jdbc.Driver 

2.3调用数据源

我们之前的ssh框架对于数据库的调用一般是写在xml文件中,而springboot将这些配置简化,可以直接通过注解在class中实现。其实原理也是一样的,也是只是将在xml中实现的数据库调用,事务管理,session工厂创建等等操作放在class实现,然后再通过@MapperScan注解将不同的数据源进行不同文件夹的映射配置,以便调用。这里直接贴上我的member数据库和order数据库的调用配置

  1. member数据库
package zzk.config.member;


import javax.sql.DataSource;

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.Qualifier;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.boot.jdbc.DataSourceBuilder;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.jdbc.datasource.DataSourceTransactionManager;

@Configuration // 说明这个类充当xml配置的作用
@MapperScan(basePackages = "zzk.member",sqlSessionTemplateRef="memberSqlSessionTemplate")
public class MemberDataSourceConfig {
	/**
	 * 创建datasource
	 */
	@Bean("memberDataSource")
	@ConfigurationProperties(prefix="spring.datasource.member")
	public DataSource memberDataSource() {
		return DataSourceBuilder.create().build();
	}
	
	/**
	 * 创建session工厂
	 * @param dataSource
	 * @return
	 * @throws Exception
	 */
	@Bean(name="memberSqlSessionFactory")
	public SqlSessionFactory memberSqlSessionFactory(@Qualifier("memberDataSource") DataSource dataSource) throws Exception{
		SqlSessionFactoryBean sessionFactoryBean=new SqlSessionFactoryBean();
		sessionFactoryBean.setDataSource(memberDataSource());
		return sessionFactoryBean.getObject();
		
	}
	
	/**
	 * 创建会员事务管理器
	 * @param dataSource
	 * @return
	 */
	@Bean(name="memberDataSourceTransactionManager")
	public DataSourceTransactionManager memberDataSourceTransactionManager(@Qualifier("memberDataSource") DataSource dataSource){
		return new DataSourceTransactionManager(dataSource);
	}
	
	/**
	 * 创建SqlSession订单模板
	 * @param sessionFactory
	 * @return
	 */
	@Bean(name="memberSqlSessionTemplate")
	public SqlSessionTemplate memberSqlSessionTemplate(@Qualifier("memberSqlSessionFactory") SqlSessionFactory sessionFactory){
		return new SqlSessionTemplate(sessionFactory);
		
	}
	
} 
  1. order数据库
package zzk.config.order;

import javax.sql.DataSource;

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.Qualifier;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.boot.jdbc.DataSourceBuilder;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.jdbc.datasource.DataSourceTransactionManager;

@Configuration // 说明这个类充当xml配置的作用
@MapperScan(basePackages = "zzk.order",sqlSessionTemplateRef="orderSqlSessionTemplate")
public class OrderDataSourceConfig {
	/**
	 * 创建datasource
	 */
	@Bean("orderDataSource")
	@ConfigurationProperties(prefix="spring.datasource.order")
	public DataSource orderDataSource() {
		return DataSourceBuilder.create().build();
	}
	
	/**
	 * 创建session工厂
	 * @param dataSource
	 * @return
	 * @throws Exception
	 */
	@Bean(name="orderSqlSessionFactory")
	public SqlSessionFactory orderSqlSessionFactory(@Qualifier("orderDataSource") DataSource dataSource) throws Exception{
		SqlSessionFactoryBean sessionFactoryBean=new SqlSessionFactoryBean();
		sessionFactoryBean.setDataSource(orderDataSource());
		return sessionFactoryBean.getObject();
		
	}
	
	/**
	 * 创建会员管理器
	 * @param dataSource
	 * @return
	 */
	@Bean(name="orderDataSourceTransactionManager")
	public DataSourceTransactionManager orderDataSourceTransactionManager(@Qualifier("orderDataSource") DataSource dataSource){
		return new DataSourceTransactionManager(dataSource);
	}
	
	/**
	 * 创建SqlSession订单模板
	 * @param sessionFactory
	 * @return
	 */
	@Bean(name="orderSqlSessionTemplate")
	public SqlSessionTemplate orderSqlSessionTemplate(@Qualifier("orderSqlSessionFactory") SqlSessionFactory sessionFactory){
		return new SqlSessionTemplate(sessionFactory);
		
	}
	
} 

2.4编写持久层

从第四点可以看出我配置的数据库调用映射文件夹分别为zzk.order和zzk.member,所以这里直接在zzk.order和zzk.member底下创建对应的mapper类。

  1. memberMapper.class
package zzk.member;

import org.apache.ibatis.annotations.Insert;
import org.apache.ibatis.annotations.Param;

public interface MemberMapper {
	@Insert("insert into user values(#{name},#{age});")
	public int insert(@Param("name") String name, @Param("age") Integer age);

} 
  1. orderMapper.class
package zzk.order;

import org.apache.ibatis.annotations.Insert;
import org.apache.ibatis.annotations.Param;

public interface OrderMapper {
	@Insert("insert into `order` values(#{id},#{money});")
	public int insert(@Param("id") Integer id, @Param("money") Integer money);

} 

2.5调用持久层

这个就没什么了,跟我们平时一样通过@controller声明类,再通过@Autowired引入持久层执行语句即可,当然这里是为了方便直接引入,省去了service层操作,而这里的mapper就是dao层。

package zzk.controller;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;

import zzk.member.MemberMapper;
import zzk.order.OrderMapper;

@Controller
public class ApplicationController {
	@Autowired
	MemberMapper memberMapper;

	@Autowired
	OrderMapper orderMapper;

	@RequestMapping("/addMember")
	@ResponseBody
	public String addMember() {
		memberMapper.insert("小白", 18);
		return null;
	}

	@RequestMapping("/addOrder")
	@ResponseBody
	public String addOrder() {
		orderMapper.insert(1, 18);
		return null;
	}

} 

2.6启动项目

编写springboot.class启动springboot项目即可。然后调用两个controller看看数据库是否添加数据,如果添加说明配置多数据源成功!

package zzk;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

@SpringBootApplication
public class Springboot {
	public static void main(String[] args) {
		SpringApplication.run(Springboot.class, args);
	}
} 

三、 整合事务管理

同上,先献上我的包结构
详细介绍springboot整合多数据源和分布式事务管理

3.1单事务管理

由于我们事务回滚一般是在业务层进行处理的,所以这里就不偷懒了,还是乖乖的建立一个service层,然后通过@Autowired引入持久层供controller层使用。
单事务管理相对来说会比较简单点。回顾前面的内容,前面我们在两个数据源的config文件各自配置了对应的事务管理bean==>DataSourceTransactionManager,所以如果需要使用引入这个事务管理即可,如下:
在controller类添加add方法

@RequestMapping("/add")
	@ResponseBody
	public String add() {
		ApplicationService.insert("小白", 0);
		return null;
	} 

然后service层也创建对应的方法

package zzk.service;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import zzk.member.MemberMapper;
import zzk.order.OrderMapper;

@Service
public class ApplicationService {
	@Autowired
	MemberMapper memberMapper;
	
	@Autowired
	OrderMapper orderMapper;

	@Transactional(transactionManager="memberDataSourceTransactionManager")
	public int insert(String name,int age){
		memberMapper.insert(name, age);
		int x=1/age;
		return age;
		
	}
} 

这样子当service出错时,便可以回滚事务,防止数据插入数据库。但是以上的代码是针对于member模块的事务操作,如果在insert的方法里加上order模块的插入操作,这时候如果service方法出错,order模块的sql会回滚吗?显然是不会的,所以为了防止这种情况的出现,我们需要整合多数据源的事务管理。

3.2分布式事务管理

这里准备使用jta-atomikos来实现分布式事务管理,大概的原理就是将各个数据源的事务管理统一注册到全局事务上以便于统一使用。

1. 引入jta-atomikos依赖

<dependency>
	<groupId>org.springframework.boot</groupId>
	<artifactId>spring-boot-starter-jta-atomikos</artifactId>
</dependency> 

2. 配置yml数据源文件

spring:
   datasource:
      member:
         url: jdbc:mysql://localhost:3306/member
         username: root
         password: tiger
         borrowConnectionTimeout: 30
         loginTimeout: 30
         maintenanceInterval: 60
         maxIdleTime: 60
         maxLifeTime: 20000
         maxPoolSize: 25
         minPoolSize: 25
         uniqueResourceName: memberDatasource
         
         
      order:
         url: jdbc:mysql://localhost:3306/order
         username: root
         password: tiger
         borrowConnectionTimeout: 30
         loginTimeout: 30
         maintenanceInterval: 60
         maxIdleTime: 60
         maxLifeTime: 20000
         maxPoolSize: 25
         minPoolSize: 25
         uniqueResourceName: orderDatasource 

这里的url就不需要加上jdbc了,因为后面我会创建实体类主动读取url地址。

3. 将yml数据源封装成实体类

package zzk.config.member;

import org.springframework.boot.context.properties.ConfigurationProperties;

import lombok.Data;

//读取配置文件的信息,读取并自动封装成实体类
@ConfigurationProperties(prefix = "spring.datasource.member")
// 自动封装set和get方法
@Data
public class MemberConfig {
	private String url;
	private String username;
	private String password;
	private int borrowConnectionTimeout;
	private int loginTimeout;
	private int maintenanceInterval;
	private int maxIdleTime;
	private int maxLifeTime;
	private int maxPoolSize;
	private int minPoolSize;
	private String testQuery;
	private String uniqueResourceName;
} 
package zzk.config.order;

import org.springframework.boot.context.properties.ConfigurationProperties;

import lombok.Data;

//读取配置文件的信息,读取并自动封装成实体类
@ConfigurationProperties(prefix="spring.datasource.order")
// 自动封装set和get方法
@Data
public class OrderConfig {
	private String url;
	private String username;
	private String password;
	private int borrowConnectionTimeout;
	private int loginTimeout;
	private int maintenanceInterval;
	private int maxIdleTime;
	private int  maxLifeTime;
	private int maxPoolSize;
	private int minPoolSize;
	private String testQuery;
	private String uniqueResourceName;
} 

这里因为变量比较多,写get和set方法看起来很繁琐,所以这里就直接使用lombok的@data注解,帮我们封装好set和get方法,以便于调用。需要注意的是lombok插件在idea本身就是支持的,但是在myeclipse和eclipse环境下需要手动安装插件才行。方法如下

1.下载lombok.jar包
2.将lombok.jar包复制到myeclipse.ini所在文件目录
3.打开myeclipse.ini在最后新增一行,加上代码:
	-javaagent:lombok.jar
4.重启myeclipse/eclipse.
5.project==>clean 重新编译项目即可 

需要引入的依赖

<dependency>
	<groupId>org.projectlombok</groupId>
	<artifactId>lombok</artifactId>
	<version>1.16.10</version>
</dependency> 

4. 注入数据源实体类

我们这里只是将数据源文件封装成实体类,还未注入使用。这里实现注入的方法有几种。第一种是在实体类的@ConfigurationProperties注解上添加@Component注解,但是如果我们数据源较多,就需要添加多次注解,使用起来不方便。所以在这里推荐第二种注解,就是在speingboot的启动类加上@EnableConfigurationProperties注解,这个注解的意思就是主动将@ConfigurationProperties注解的类注入使用。第三种就是每次使用这个类的时候直接通过@Autowired注入使用
实现代码如下

package zzk;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.scheduling.annotation.EnableScheduling;

import zzk.config.member.MemberConfig;
import zzk.config.order.OrderConfig;

@SpringBootApplication
@EnableScheduling
@EnableConfigurationProperties({MemberConfig.class,OrderConfig.class})
public class Springboot {
	public static void main(String[] args) {
		SpringApplication.run(Springboot.class, args);
	}
} 

5. 多数据源事务注册到全局事务上

重写MemberDataSourceConfig.java的memberDataSource方法

 @Bean("memberDataSource")
	// @ConfigurationProperties(prefix="spring.datasource.member")
	public DataSource memberDataSource(MemberConfig memberConfig) throws SQLException {
		// 创建xaDatasource
		MysqlXADataSource mysqlXADataSource = new MysqlXADataSource();
		mysqlXADataSource.setUrl(memberConfig.getUrl());
		mysqlXADataSource.setPinGlobalTxToPhysicalConnection(true);
		mysqlXADataSource.setUser(memberConfig.getUsername());
		mysqlXADataSource.setPassword(memberConfig.getPassword());

		// 注册到全局事务上
		AtomikosDataSourceBean xaDataSource = new AtomikosDataSourceBean();
		xaDataSource.setXaDataSource(mysqlXADataSource);
		xaDataSource.setUniqueResourceName(memberConfig.getUniqueResourceName());
		xaDataSource.setMaxPoolSize(memberConfig.getMaxPoolSize());
		xaDataSource.setMinPoolSize(memberConfig.getMinPoolSize());
		xaDataSource.setMaxLifetime(memberConfig.getMaxLifeTime());
		xaDataSource.setBorrowConnectionTimeout(memberConfig.getBorrowConnectionTimeout());
		xaDataSource.setLoginTimeout(memberConfig.getLoginTimeout());
		xaDataSource.setMaintenanceInterval(memberConfig.getMaintenanceInterval());
		xaDataSource.setMaxIdleTime(memberConfig.getMaxIdleTime());
		xaDataSource.setTestQuery(memberConfig.getTestQuery());

		return xaDataSource;
	} 

同理重写OrderDataSourceConfig.java的orderDataSource方法

@Bean("orderDataSource")
	// @ConfigurationProperties(prefix="spring.datasource.order")
	public DataSource orderDataSource(OrderConfig orderConfig) throws SQLException {
		// 创建xaDatasource
		MysqlXADataSource mysqlXADataSource = new MysqlXADataSource();
		mysqlXADataSource.setUrl(orderConfig.getUrl());
		mysqlXADataSource.setPinGlobalTxToPhysicalConnection(true);
		mysqlXADataSource.setUser(orderConfig.getUsername());
		mysqlXADataSource.setPassword(orderConfig.getPassword());

		// 注册到全局事务上
		AtomikosDataSourceBean xaDataSource = new AtomikosDataSourceBean();
		xaDataSource.setXaDataSource(mysqlXADataSource);
		xaDataSource.setUniqueResourceName(orderConfig.getUniqueResourceName());
		xaDataSource.setMaxPoolSize(orderConfig.getMaxPoolSize());
		xaDataSource.setMinPoolSize(orderConfig.getMinPoolSize());
		xaDataSource.setMaxLifetime(orderConfig.getMaxLifeTime());
		xaDataSource.setBorrowConnectionTimeout(orderConfig.getBorrowConnectionTimeout());
		xaDataSource.setLoginTimeout(orderConfig.getLoginTimeout());
		xaDataSource.setMaintenanceInterval(orderConfig.getMaintenanceInterval());
		xaDataSource.setMaxIdleTime(orderConfig.getMaxIdleTime());
		xaDataSource.setTestQuery(orderConfig.getTestQuery());

		return xaDataSource;
	} 

当然,这里既然将事务注册到全局事务上,那每个数据源的事务bean就没有存在的必要了,这里将每个数据源的事务bean注释,避免调用事务的时候报错(存在多事务),这里贴出修改完的MemberDataSourceConfig和orderDataSourceConfig代码

package zzk.config.member;

import java.sql.SQLException;

import javax.sql.DataSource;

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.Qualifier;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.boot.jdbc.DataSourceBuilder;
import org.springframework.boot.jta.atomikos.AtomikosDataSourceBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.jdbc.datasource.DataSourceTransactionManager;

import com.mysql.jdbc.jdbc2.optional.MysqlXADataSource;

//说明这个类充当xml配置的作用
@Configuration 
// 数据源的作用范围
@MapperScan(basePackages = "zzk.member", sqlSessionTemplateRef = "memberSqlSessionTemplate")
public class MemberDataSourceConfig {
	/**
	 * 创建datasource
	 * 
	 * @throws SQLException
	 */
	@Bean("memberDataSource")
	// @ConfigurationProperties(prefix="spring.datasource.member")
	public DataSource memberDataSource(MemberConfig memberConfig) throws SQLException {
		// 创建xaDatasource
		MysqlXADataSource mysqlXADataSource = new MysqlXADataSource();
		mysqlXADataSource.setUrl(memberConfig.getUrl());
		mysqlXADataSource.setPinGlobalTxToPhysicalConnection(true);
		mysqlXADataSource.setUser(memberConfig.getUsername());
		mysqlXADataSource.setPassword(memberConfig.getPassword());

		// 注册到全局事务上
		AtomikosDataSourceBean xaDataSource = new AtomikosDataSourceBean();
		xaDataSource.setXaDataSource(mysqlXADataSource);
		xaDataSource.setUniqueResourceName(memberConfig.getUniqueResourceName());
		xaDataSource.setMaxPoolSize(memberConfig.getMaxPoolSize());
		xaDataSource.setMinPoolSize(memberConfig.getMinPoolSize());
		xaDataSource.setMaxLifetime(memberConfig.getMaxLifeTime());
		xaDataSource.setBorrowConnectionTimeout(memberConfig.getBorrowConnectionTimeout());
		xaDataSource.setLoginTimeout(memberConfig.getLoginTimeout());
		xaDataSource.setMaintenanceInterval(memberConfig.getMaintenanceInterval());
		xaDataSource.setMaxIdleTime(memberConfig.getMaxIdleTime());
		xaDataSource.setTestQuery(memberConfig.getTestQuery());

		return xaDataSource;
	}

	/**
	 * 创建session工厂
	 * 
	 * @param dataSource
	 * @return
	 * @throws Exception
	 */
	@Bean(name = "memberSqlSessionFactory")
	public SqlSessionFactory memberSqlSessionFactory(@Qualifier("memberDataSource") DataSource dataSource)
			throws Exception {
		SqlSessionFactoryBean sessionFactoryBean = new SqlSessionFactoryBean();
		sessionFactoryBean.setDataSource(dataSource);
		return sessionFactoryBean.getObject();

	}

//	/**
//	 * 创建会员事务管理器
//	 * 
//	 * @param dataSource
//	 * @return
//	 */
//	@Bean(name = "memberDataSourceTransactionManager")
//	public DataSourceTransactionManager memberDataSourceTransactionManager(
//			@Qualifier("memberDataSource") DataSource dataSource) {
//		return new DataSourceTransactionManager(dataSource);
//	}

	/**
	 * 创建SqlSession订单模板
	 * 
	 * @param sessionFactory
	 * @return
	 */
	@Bean(name = "memberSqlSessionTemplate")
	public SqlSessionTemplate memberSqlSessionTemplate(
			@Qualifier("memberSqlSessionFactory") SqlSessionFactory sessionFactory) {
		return new SqlSessionTemplate(sessionFactory);

	}

} 
package zzk.config.order;

import java.sql.SQLException;

import javax.sql.DataSource;

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.Qualifier;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.boot.jdbc.DataSourceBuilder;
import org.springframework.boot.jta.atomikos.AtomikosDataSourceBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.jdbc.datasource.DataSourceTransactionManager;

import com.mysql.jdbc.jdbc2.optional.MysqlXADataSource;

//说明这个类充当xml配置的作用
@Configuration
// 数据源的作用范围
@MapperScan(basePackages = "zzk.order", sqlSessionTemplateRef = "orderSqlSessionTemplate")
public class OrderDataSourceConfig {
	/**
	 * 创建datasource
	 * 
	 * @throws SQLException
	 */
	@Bean("orderDataSource")
	// @ConfigurationProperties(prefix="spring.datasource.order")
	public DataSource orderDataSource(OrderConfig orderConfig) throws SQLException {
		// 创建xaDatasource
		MysqlXADataSource mysqlXADataSource = new MysqlXADataSource();
		mysqlXADataSource.setUrl(orderConfig.getUrl());
		mysqlXADataSource.setPinGlobalTxToPhysicalConnection(true);
		mysqlXADataSource.setUser(orderConfig.getUsername());
		mysqlXADataSource.setPassword(orderConfig.getPassword());

		// 注册到全局事务上
		AtomikosDataSourceBean xaDataSource = new AtomikosDataSourceBean();
		xaDataSource.setXaDataSource(mysqlXADataSource);
		xaDataSource.setUniqueResourceName(orderConfig.getUniqueResourceName());
		xaDataSource.setMaxPoolSize(orderConfig.getMaxPoolSize());
		xaDataSource.setMinPoolSize(orderConfig.getMinPoolSize());
		xaDataSource.setMaxLifetime(orderConfig.getMaxLifeTime());
		xaDataSource.setBorrowConnectionTimeout(orderConfig.getBorrowConnectionTimeout());
		xaDataSource.setLoginTimeout(orderConfig.getLoginTimeout());
		xaDataSource.setMaintenanceInterval(orderConfig.getMaintenanceInterval());
		xaDataSource.setMaxIdleTime(orderConfig.getMaxIdleTime());
		xaDataSource.setTestQuery(orderConfig.getTestQuery());

		return xaDataSource;
	}

	/**
	 * 创建session工厂
	 * 
	 * @param dataSource
	 * @return
	 * @throws Exception
	 */
	@Bean(name = "orderSqlSessionFactory")
	public SqlSessionFactory orderSqlSessionFactory(@Qualifier("orderDataSource") DataSource dataSource)
			throws Exception {
		SqlSessionFactoryBean sessionFactoryBean = new SqlSessionFactoryBean();
		sessionFactoryBean.setDataSource(dataSource);
		return sessionFactoryBean.getObject();

	}

	// /**
	// * 创建会员管理器
	// * @param dataSource
	// * @return
	// */
	// @Bean(name="orderDataSourceTransactionManager")
	// public DataSourceTransactionManager
	// orderDataSourceTransactionManager(@Qualifier("orderDataSource")
	// DataSource dataSource){
	// return new DataSourceTransactionManager(dataSource);
	// }

	/**
	 * 创建SqlSession订单模板
	 * 
	 * @param sessionFactory
	 * @return
	 */
	@Bean(name = "orderSqlSessionTemplate")
	public SqlSessionTemplate orderSqlSessionTemplate(
			@Qualifier("orderSqlSessionFactory") SqlSessionFactory sessionFactory) {
		return new SqlSessionTemplate(sessionFactory);

	}

} 

6. 调用全局事务

同单事务管理,代码简单就不多说了,直接贴出代码
controller层

@RequestMapping("/add")
	@ResponseBody
	public String add() {
		ApplicationService.insert("小白", 0);
		return null;
	} 

service层

package zzk.service;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import zzk.member.MemberMapper;
import zzk.order.OrderMapper;

@Service
public class ApplicationService {
	@Autowired
	MemberMapper memberMapper;
	
	@Autowired
	OrderMapper orderMapper;

	@Transactional
	public int insert(String name,int age){
		memberMapper.insert(name, age);
		orderMapper.insert(1, 1);
		int x=1/age;
		return age;
		
	}
} 

注意,这个地方调用事务的时候已经不需要再申明是哪个事务了,因为我们现在数据源独立的事务已经被注视了,剩下的就只有一个全局事务!!!!

这时候测试下,发现service出错的话,两个数据库的sql语句都会回滚,说明配置成功!!!
如果有疑问或者有什么错误可以指出来,的可以在下方留言,共同进步!!!

本文地址:https://blog.csdn.net/weixin_40496191/article/details/108866647