分布式事务解决方案的问题,

分布式事务产生的原因:

多个不同的服务连接不同的数据源 ,做分布式事务的管理。

这种情况是连接两个数据源的情况,然后事务管理器是这样的 只管理了test02的这端业务代码。所以test02的这个会回滚!

但是test01会入库哦

这属于传统的分布式事务解决方案

   使用springboot+jta+atomikos 分布式事物管理 (不适合微服务,需要拿到数据源然后注册到同一个全局事务里面去)

好了废话不多说,动手撸代码!

引入的jar:

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

配置文件也要修改:

application.properties:

# Mysql 1
mysql.datasource.test1.url = jdbc:mysql://localhost:3306/test01?useUnicode=true&characterEncoding=utf-8
mysql.datasource.test1.username = root
mysql.datasource.test1.password = root mysql.datasource.test1.minPoolSize = 3
mysql.datasource.test1.maxPoolSize = 25
mysql.datasource.test1.maxLifetime = 20000
mysql.datasource.test1.borrowConnectionTimeout = 30
mysql.datasource.test1.loginTimeout = 30
mysql.datasource.test1.maintenanceInterval = 60
mysql.datasource.test1.maxIdleTime = 60 # Mysql 2
mysql.datasource.test2.url =jdbc:mysql://localhost:3306/test02?useUnicode=true&characterEncoding=utf-8
mysql.datasource.test2.username =root
mysql.datasource.test2.password =root mysql.datasource.test2.minPoolSize = 3
mysql.datasource.test2.maxPoolSize = 25
mysql.datasource.test2.maxLifetime = 20000
mysql.datasource.test2.borrowConnectionTimeout = 30
mysql.datasource.test2.loginTimeout = 30
mysql.datasource.test2.maintenanceInterval = 60
mysql.datasource.test2.maxIdleTime = 60

 然后创建包:com.toov5.configure

底层原理是使用的2PC

package com.toov5.configure;

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

import lombok.Data;

@Data
@ConfigurationProperties(prefix = "mysql.datasource.test1")
public class DBConfig1 { private String url;
private String username;
private String password;
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.toov5.configure;

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

import lombok.Data;
//读取解析配置文件,获取值
@Data
@ConfigurationProperties(prefix = "mysql.datasource.test2")
public class DBConfig2 { private String url;
private String username;
private String password;
private int minPoolSize;
private int maxPoolSize;
private int maxLifetime;
private int borrowConnectionTimeout;
private int loginTimeout;
private int maintenanceInterval;
private int maxIdleTime;
private String testQuery;
}

datasource包下面:

package com.toov5.datasource;

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.context.annotation.Bean;
import org.springframework.context.annotation.Configuration; import com.atomikos.jdbc.AtomikosDataSourceBean;
import com.mysql.jdbc.jdbc2.optional.MysqlXADataSource;
import com.toov5.configure.DBConfig1; @Configuration
// basePackages 最好分开配置 如果放在同一个文件夹可能会报错
//跟之前都一样。扫包然后指定工厂
//没有配置事务管理器,相当于将本地事务注册到Atomikos全局事务
@MapperScan(basePackages = "com.toov5.test01", sqlSessionTemplateRef = "testSqlSessionTemplate")
public class MyBatisConfig1 { // 配置数据源 @Bean(name = "testDataSource")
public DataSource testDataSource(DBConfig1 testConfig) throws SQLException {
MysqlXADataSource mysqlXaDataSource = new MysqlXADataSource();
mysqlXaDataSource.setUrl(testConfig.getUrl());
mysqlXaDataSource.setPinGlobalTxToPhysicalConnection(true);
mysqlXaDataSource.setPassword(testConfig.getPassword());
mysqlXaDataSource.setUser(testConfig.getUsername());
mysqlXaDataSource.setPinGlobalTxToPhysicalConnection(true); //创建Atomikos全局事务,所有的事务注册进来
AtomikosDataSourceBean xaDataSource = new AtomikosDataSourceBean();
xaDataSource.setXaDataSource(mysqlXaDataSource);
xaDataSource.setUniqueResourceName("testDataSource"); //testDataSource这个数据源的注册 xaDataSource.setMinPoolSize(testConfig.getMinPoolSize());
xaDataSource.setMaxPoolSize(testConfig.getMaxPoolSize());
xaDataSource.setMaxLifetime(testConfig.getMaxLifetime());
xaDataSource.setBorrowConnectionTimeout(testConfig.getBorrowConnectionTimeout());
xaDataSource.setLoginTimeout(testConfig.getLoginTimeout());
xaDataSource.setMaintenanceInterval(testConfig.getMaintenanceInterval());
xaDataSource.setMaxIdleTime(testConfig.getMaxIdleTime());
xaDataSource.setTestQuery(testConfig.getTestQuery());
return xaDataSource;
} @Bean(name = "testSqlSessionFactory")
public SqlSessionFactory testSqlSessionFactory(@Qualifier("testDataSource") DataSource dataSource)
throws Exception {
SqlSessionFactoryBean bean = new SqlSessionFactoryBean();
bean.setDataSource(dataSource);
return bean.getObject();
} @Bean(name = "testSqlSessionTemplate")
public SqlSessionTemplate testSqlSessionTemplate(
@Qualifier("testSqlSessionFactory") SqlSessionFactory sqlSessionFactory) throws Exception {
return new SqlSessionTemplate(sqlSessionFactory);
}
}
package com.toov5.datasource;

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.context.annotation.Bean;
import org.springframework.context.annotation.Configuration; import com.atomikos.jdbc.AtomikosDataSourceBean;
import com.mysql.jdbc.jdbc2.optional.MysqlXADataSource;
import com.toov5.configure.DBConfig2; @Configuration
@MapperScan(basePackages = "com.toov5.test02", sqlSessionTemplateRef = "test2SqlSessionTemplate")
public class MyBatisConfig2 { // 配置数据源
@Bean(name = "test2DataSource")
public DataSource testDataSource(DBConfig2 testConfig) throws SQLException {
MysqlXADataSource mysqlXaDataSource = new MysqlXADataSource();
mysqlXaDataSource.setUrl(testConfig.getUrl());
mysqlXaDataSource.setPinGlobalTxToPhysicalConnection(true);
mysqlXaDataSource.setPassword(testConfig.getPassword());
mysqlXaDataSource.setUser(testConfig.getUsername());
mysqlXaDataSource.setPinGlobalTxToPhysicalConnection(true); AtomikosDataSourceBean xaDataSource = new AtomikosDataSourceBean();
xaDataSource.setXaDataSource(mysqlXaDataSource);
xaDataSource.setUniqueResourceName("test2DataSource"); xaDataSource.setMinPoolSize(testConfig.getMinPoolSize());
xaDataSource.setMaxPoolSize(testConfig.getMaxPoolSize());
xaDataSource.setMaxLifetime(testConfig.getMaxLifetime());
xaDataSource.setBorrowConnectionTimeout(testConfig.getBorrowConnectionTimeout());
xaDataSource.setLoginTimeout(testConfig.getLoginTimeout());
xaDataSource.setMaintenanceInterval(testConfig.getMaintenanceInterval());
xaDataSource.setMaxIdleTime(testConfig.getMaxIdleTime());
xaDataSource.setTestQuery(testConfig.getTestQuery());
return xaDataSource;
} @Bean(name = "test2SqlSessionFactory")
public SqlSessionFactory testSqlSessionFactory(@Qualifier("test2DataSource") DataSource dataSource)
throws Exception {
SqlSessionFactoryBean bean = new SqlSessionFactoryBean();
bean.setDataSource(dataSource);
return bean.getObject();
} @Bean(name = "test2SqlSessionTemplate")
public SqlSessionTemplate testSqlSessionTemplate(
@Qualifier("test2SqlSessionFactory") SqlSessionFactory sqlSessionFactory) throws Exception {
return new SqlSessionTemplate(sqlSessionFactory);
}
}

service中的事务管理不需要去写了!

package com.toov5.test02.service02;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional; import com.toov5.test01.mappertest01.UserMapperTest01;
import com.toov5.test02.mappertest02.UserMapperTest02; import lombok.extern.slf4j.Slf4j; @Service
@Slf4j
public class UserService02 {
@Autowired
private UserMapperTest01 userMapperTest01;
@Autowired
private UserMapperTest02 userMapperTest02; @Transactionalpublic int test01Andtest02(String name, Integer age){
//连接两个数据源
int result1 = userMapperTest01.insert(name, age);
int result2 = userMapperTest02.insert(name, age);
int i = 1/0;
int result = result1+result2;
return result;
} }

目录结构:

项目启动类

package com.toov5.app;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.context.properties.EnableConfigurationProperties; import com.toov5.configure.DBConfig1;
import com.toov5.configure.DBConfig2; @SpringBootApplication(scanBasePackages={"com.toov5.*"})
@EnableConfigurationProperties(value = { DBConfig1.class, DBConfig2.class })
//开启读取配置文件,启动时候去读取配置文件
public class app { public static void main(String[] args) {
SpringApplication.run(app.class, args);
} }

ok,到此为止。是不是很简单呀~

Spring Boot2.0之多数据源分布式事务问题的更多相关文章

  1. Spring 3.0 + Atomikos构建jta分布式事务

    Spring3.0已经不再支持jtom了,不过我们可以用第三方开源软件atomikos(http://www.atomikos.com/)来实现.Atomikos是目前在分布式事务管理中做得相当不错的 ...

  2. Spring Boot2.0之多数据源事务管理

    结合前面做的小项目,如果我把test01 test02下面的 service 都加了 事务的注解 这样启动时候会报错! 事务管理器里面不能有两个事务!!!! 这时候需要用  @Transactiona ...

  3. 【spring colud】spring cloud微服务项目搭建【spring boot2.0】

    spring cloud微服务项目搭建 =================================== 示例版本: 1.spring boot 2.0版本 2.开发工具 IntellJ IDE ...

  4. Spring Boot2.0 整合 Kafka

    Kafka 概述 Apache Kafka 是一个分布式流处理平台,用于构建实时的数据管道和流式的应用.它可以让你发布和订阅流式的记录,可以储存流式的记录,并且有较好的容错性,可以在流式记录产生时就进 ...

  5. Spring Boot2.0之整合事物管理

    首先Spring 事务分类 1.声明事务  原理:基于编程事务的 2.编程事务  指定范围 扫包去解决 3.事务原理:AOP技术   通过环绕通知进行了拦截 使用Spring 事务注意事项: 不要tr ...

  6. Spring Boot2.0 设置拦截器

    所有功能完成 配置登录认证 配置拦截器 在spring boot2.0 之后 通过继承这个WebMvcConfigurer类 就可以完成拦截 新建包com.example.interceptor; 创 ...

  7. Spring Boot2.0 静态资源被拦截问题

    在Spring Boot2.0+的版本中,只要用户自定义了拦截器,则静态资源会被拦截.但是在spring1.0+的版本中,是不会拦截静态资源的. 因此,在使用Spring Boot2.0+时,配置拦截 ...

  8. Spring Boot2.0使用Spring Security

     一.Spring Secutity简介     Spring 是一个非常流行和成功的 Java 应用开发框架.Spring Security 基于 Spring 框架,提供了一套 Web 应用安全性 ...

  9. spring boot2.0(一 ) 基础环境搭建

    1.基础配置 开发环境:window jdk版本:1.8(spring boot2.0最低要求1.8) 开发工具:eclipse 构建方式:maven3 2.POM配置文件 <project x ...

随机推荐

  1. docker selinux-enabled作用

    一.现象 在docker中有一个运行选项是selinux-enabled.这个选项的作用是啥? 简而言之,它提供了对docker容器中进程的selinux的控制支持.下面举例说明. 首先按照官方文档的 ...

  2. windows8开发-关于wp7应用迁移到win8 metro风格

    虽然微软说,wp7应用移植到win8上面是比较简单,只需要修改部分API和设计原则上的细节,同时它也提供了一份比较简洁的参考文档: 而实际上这种移植的工作量还是不小的,尤其当应用引用了较多底层的API ...

  3. remove-duplicates-from-sorted-array-ii——去除重复

    Follow up for "Remove Duplicates":What if duplicates are allowed at most twice? For exampl ...

  4. struts2获取服务器临时目录

      CreateTime--2017年9月7日08:57:39 Author:Marydon struts2获取服务器(tomcat.WebLogic)的临时目录 需要导入: import java. ...

  5. 高速掌握Lua 5.3 —— Lua与C之间的交互概览

    Q:什么是Lua的虚拟栈? A:C与Lua之间通信关键内容在于一个虚拟的栈.差点儿全部的调用都是对栈上的值进行操作,全部C与Lua之间的数据交换也都通过这个栈来完毕.另外,你也能够使用栈来保存暂时变量 ...

  6. spring(16)------spring的数据源配置

    在spring中,通过XML的形式实现数据源的注入有三种形式. 一.使用spring自带的DriverManagerDataSource 使用DriverManagerDataSource配置数据源与 ...

  7. 关于meta标签的name="viewport" 概述

    <meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scal ...

  8. uwsgi报错:listen queue of socket ...

    Linux默认的socket链接为128,uwsgi默人的链接为100 需要修改系统默认的配置参数, 然后修改uwsgi配置:listen参数:1024

  9. oracle不同用户间访问表不添加用户名(模式)前缀

    默认的情况下,oracle里面的用户A,要访问用户B的表需要带用户B的前缀,如访问用户B的 user表,需要这样访问 select * from B.user;如果想要不添加用户前缀,需要这样处理: ...

  10. 牛牛有一个鱼缸。鱼缸里面已经有n条鱼,每条鱼的大小为fishSize[i] (1 ≤ i ≤ n,均为正整数),牛牛现在想把新捕捉的鱼放入鱼缸。鱼缸内存在着大鱼吃小鱼的定律。经过观察,牛牛发现一条鱼A的大小为另外一条鱼B大小的2倍到10倍(包括2倍大小和10倍大小),鱼A会吃掉鱼B。考虑到这个,牛牛要放入的鱼就需要保证:1、放进去的鱼是安全的,不会被其他鱼吃掉 2、这条鱼放进去也不能吃掉其他鱼

    // ConsoleApplication5.cpp : 定义控制台应用程序的入口点. // #include<vector> #include<algorithm> #inc ...