详细介绍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数据库的调用配置
- 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);
}
}
- 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类。
- 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);
}
- 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);
}
}
三、 整合事务管理
同上,先献上我的包结构
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
上一篇: pr视频怎么添加背景图? premiere视频换背景的技巧
下一篇: Python实现多任务进程示例