springboot+jta+atomikos分布式多数据源事务管理 (SQLserver)

本文涉及的产品
RDS SQL Server Serverless,2-4RCU 50GB 3个月
推荐场景:
云数据库 RDS SQL Server,基础系列 2核4GB
简介: 在我上一篇博客的项目基础上做更改springboot多数据源分包式实现首先我们来试一下没有更改的情况下

在我上一篇博客的项目基础上做更改

springboot多数据源分包式实现

首先我们来试一下没有更改的情况下

1.@Service
public class User2Service {
  @Autowired
  private User2Mapper mapper2;
  @Autowired
  private User2Mapper mapper1;
  @Transactional
  public void insert() {
    mapper1.insert();
    int a = 1/0;
    mapper2.insert();
  }
}
@Repository
public interface User1Mapper{
  @Insert("insert into user_demo values('事务管理','1')")
  public void insert();
}
@Repository
public interface User2Mapper {
  @Insert("insert into user_demo values('事务管理','2')")
  public void insert();
}

在User2Service中同时对User1Mapper 和User2Mapper进行事务管理,在中间的除零异常出现后,数据还是被保存到了数据库,但是只是UserMapper2的数据被保存到了数据库,UserMapper1的数据被回滚,这种情况下默认是只对@Primary的数据源进行事务管理



那我们就把事务管理交给atomikos


首先application.properties配置文件重新写一下,依赖引入一下

sqlserver.datasource.test1.url=jdbc:sqlserver://localhost:1433;DatabaseName=Test
sqlserver.datasource.test1.username=sa
sqlserver.datasource.test1.password=vhukze
sqlserver.datasource.test1.minPoolSize=3
sqlserver.datasource.test1.maxPoolSize=25
sqlserver.datasource.test1.maxLifetime=20000
sqlserver.datasource.test1.borrowConnectionTimeout=30
sqlserver.datasource.test1.loginTimeout=30
sqlserver.datasource.test1.maintenanceInterval=60
sqlserver.datasource.test1.maxIdleTime=60
sqlserver.datasource.test1.testQuery=select 1
#mybatis  配置文件
#sqlserver.datasource.test1.mapper-locations=classpath:mapper1/*.xml
#mybatis 对应的实体类
#sqlserver.datasource.test1.type-aliases-package=com.wangye.spbootjtaautomatic.model1
#sqlserver2
sqlserver.datasource.test2.url=jdbc:sqlserver://localhost:1433;DatabaseName=Test1
sqlserver.datasource.test2.username=sa
sqlserver.datasource.test2.password=vhukze
sqlserver.datasource.test2.minPoolSize=3
sqlserver.datasource.test2.maxPoolSize=25
sqlserver.datasource.test2.maxLifetime=20000
sqlserver.datasource.test2.borrowConnectionTimeout=30
sqlserver.datasource.test2.loginTimeout=30
sqlserver.datasource.test2.maintenanceInterval=60
sqlserver.datasource.test2.maxIdleTime=60
sqlserver.datasource.test2.testQuery=select 1
#mybatis  配置文件
#sqlserver.datasource.test2.mapper-locations=classpath:mapper2/*.xml
#mybatis 对应的实体类
#sqlserver.datasource.test2.type-aliases-package=com.wangye.spbootjtaautomatic.model2
<dependency>
      <groupId>org.springframework.boot</groupId>
      <artifactId>spring-boot-starter-jta-atomikos</artifactId>
</dependency>

我这里没有建实体类也没有用配置文件 。

然后把之前的数据源配置类注释了 删了也行 我这里就注释了。

新建两个配置类

package com.vhukze.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 org.springframework.context.annotation.Primary;
import com.atomikos.jdbc.AtomikosDataSourceBean;
import com.microsoft.sqlserver.jdbc.SQLServerXADataSource;
import com.vhukze.config.DBConfig1;
/**
* @author zsz
* @version 
* @创建时间:2019年9月3日 上午9:31:28
*/
@Configuration
@MapperScan(basePackages="com.vhukze.test1",sqlSessionTemplateRef="test1SqlSessionTemplate")
public class TestMybatisConfig1 {
  @Primary
  @Bean(name="test1DataSource")
  public DataSource testDataSource(DBConfig1 testConfig) throws SQLException {
    SQLServerXADataSource sqlServerXADataSource = new SQLServerXADataSource();
    sqlServerXADataSource.setURL(testConfig.getUrl());
    sqlServerXADataSource.setUser(testConfig.getUsername());
    sqlServerXADataSource.setPassword(testConfig.getPassword());
    AtomikosDataSourceBean atomikosDataSourceBean = new AtomikosDataSourceBean();
    atomikosDataSourceBean.setXaDataSource(sqlServerXADataSource);
    atomikosDataSourceBean.setUniqueResourceName("test1DataSource");
    atomikosDataSourceBean.setMinPoolSize(testConfig.getMinPoolSize());
    atomikosDataSourceBean.setMaxPoolSize(testConfig.getMaxPoolSize());
    atomikosDataSourceBean.setMaxLifetime(testConfig.getMaxLifeTime());
    atomikosDataSourceBean.setBorrowConnectionTimeout(testConfig.getBorrowConnectionTimeOut());
    atomikosDataSourceBean.setLoginTimeout(testConfig.getLoginTimeOut());
    atomikosDataSourceBean.setMaintenanceInterval(testConfig.getMaintenanceInterval());
    atomikosDataSourceBean.setMaxIdleTime(testConfig.getMaxIdleTime());
    atomikosDataSourceBean.setTestQuery(testConfig.getTestQuery());
    return atomikosDataSourceBean;
  }
  @Bean(name="test1SqlSessionFactory")
  public SqlSessionFactory testSqlSessionFactory(@Qualifier("test1DataSource") DataSource dataSource) throws Exception { 
    SqlSessionFactoryBean bean = new SqlSessionFactoryBean();
    bean.setDataSource(dataSource);
    return bean.getObject();
  }
  @Bean(name="test1SqlSessionTemplate")
  public SqlSessionTemplate testSqlSessionTemplate(@Qualifier("test1SqlSessionFactory") SqlSessionFactory sqlSessionFactory) { 
    return new SqlSessionTemplate(sqlSessionFactory);
  }
}

第二个就把这里面的test1和DBConfig1改成test2和DBConfig2 就好了,跟之前的配置类差不多,就是把DataSource交给atomikos管理了

然后创建一下里面需要用到的配置实体类DBConfig1和DBConfig2 在新建的一个config包下

package com.vhukze.config;
import org.springframework.boot.context.properties.ConfigurationProperties;
/**
* @author zsz
* @version 
* @创建时间:2019年9月3日 上午9:55:23
*/
@ConfigurationProperties(prefix="sqlserver.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;
  get set 方法
}

这个跟上面一样    DBConfig2 就把注解里面的test1改成test2

在启动类添加扫描config包 还有一个什么开启配置文件 就把两个字节码文件给它就行

1.@SpringBootApplication
@ComponentScan(basePackages= {"com.vhukze.config","com.vhukze.controller","com.vhukze.test1.service","com.vhukze.test2.service","com.vhukze.datasource"})
@MapperScan({"com.vhukze.test1.mapper","com.vhukze.test2.mapper"})
@EnableConfigurationProperties(value = {DBConfig1.class,DBConfig2.class})
public class App {
  public static void main(String[] args) {
    SpringApplication.run(App.class, args);
  }
}

到这里就改完了配置,也没多麻烦。


启动项目访问映射路径------报错……


无法创建 XA 控制连接。错误:“找不到存储过程 'master..xp_sqljdbc_xa_init_ex'


这是因为sql server库的服务器没有配置XA事务和安装JDBC插件


解决步骤写在了另一篇博客中-->无法创建XA控制连接


而且我之前用的是公司服务器中的SQLserver,然后换成本机的了,但是不知道连接密码,解决办法


-->SQLserver改登录密码


都弄好之后测试成功,可以同时管理两个数据源的事务


相关实践学习
使用SQL语句管理索引
本次实验主要介绍如何在RDS-SQLServer数据库中,使用SQL语句管理索引。
SQL Server on Linux入门教程
SQL Server数据库一直只提供Windows下的版本。2016年微软宣布推出可运行在Linux系统下的SQL Server数据库,该版本目前还是早期预览版本。本课程主要介绍SQLServer On Linux的基本知识。 相关的阿里云产品:云数据库RDS&nbsp;SQL Server版 RDS SQL Server不仅拥有高可用架构和任意时间点的数据恢复功能,强力支撑各种企业应用,同时也包含了微软的License费用,减少额外支出。 了解产品详情:&nbsp;https://www.aliyun.com/product/rds/sqlserver
相关文章
|
4月前
|
缓存 NoSQL Java
SpringBoot整合Redis、以及缓存穿透、缓存雪崩、缓存击穿的理解分布式情况下如何添加分布式锁 【续篇】
这篇文章是关于如何在SpringBoot应用中整合Redis并处理分布式场景下的缓存问题,包括缓存穿透、缓存雪崩和缓存击穿。文章详细讨论了在分布式情况下如何添加分布式锁来解决缓存击穿问题,提供了加锁和解锁的实现过程,并展示了使用JMeter进行压力测试来验证锁机制有效性的方法。
SpringBoot整合Redis、以及缓存穿透、缓存雪崩、缓存击穿的理解分布式情况下如何添加分布式锁 【续篇】
|
25天前
|
缓存 NoSQL Java
Spring Boot中的分布式缓存方案
Spring Boot提供了简便的方式来集成和使用分布式缓存。通过Redis和Memcached等缓存方案,可以显著提升应用的性能和扩展性。合理配置和优化缓存策略,可以有效避免常见的缓存问题,保证系统的稳定性和高效运行。
43 3
|
1月前
|
存储 Java 关系型数据库
在Spring Boot中整合Seata框架实现分布式事务
可以在 Spring Boot 中成功整合 Seata 框架,实现分布式事务的管理和处理。在实际应用中,还需要根据具体的业务需求和技术架构进行进一步的优化和调整。同时,要注意处理各种可能出现的问题,以保障分布式事务的顺利执行。
57 6
|
1月前
|
Java 数据库连接
SpringBoot配置多数据源实战
第四届光学与机器视觉国际学术会议(ICOMV 2025) 2025 4th International Conference on Optics and Machine Vision
64 8
|
4月前
|
缓存 NoSQL Java
SpringBoot整合Redis、以及缓存穿透、缓存雪崩、缓存击穿的理解、如何添加锁解决缓存击穿问题?分布式情况下如何添加分布式锁
这篇文章介绍了如何在SpringBoot项目中整合Redis,并探讨了缓存穿透、缓存雪崩和缓存击穿的问题以及解决方法。文章还提供了解决缓存击穿问题的加锁示例代码,包括存在问题和问题解决后的版本,并指出了本地锁在分布式情况下的局限性,引出了分布式锁的概念。
SpringBoot整合Redis、以及缓存穿透、缓存雪崩、缓存击穿的理解、如何添加锁解决缓存击穿问题?分布式情况下如何添加分布式锁
|
3月前
|
运维 NoSQL Java
SpringBoot接入轻量级分布式日志框架GrayLog技术分享
在当今的软件开发环境中,日志管理扮演着至关重要的角色,尤其是在微服务架构下,分布式日志的统一收集、分析和展示成为了开发者和运维人员必须面对的问题。GrayLog作为一个轻量级的分布式日志框架,以其简洁、高效和易部署的特性,逐渐受到广大开发者的青睐。本文将详细介绍如何在SpringBoot项目中接入GrayLog,以实现日志的集中管理和分析。
297 1
|
4月前
|
Java 微服务 Spring
SpringBoot+Vue+Spring Cloud Alibaba 实现大型电商系统【分布式微服务实现】
文章介绍了如何利用Spring Cloud Alibaba快速构建大型电商系统的分布式微服务,包括服务限流降级等主要功能的实现,并通过注解和配置简化了Spring Cloud应用的接入和搭建过程。
SpringBoot+Vue+Spring Cloud Alibaba 实现大型电商系统【分布式微服务实现】
|
4月前
|
Java
SpringBoot 配置多数据源
SpringBoot 配置多数据源
42 0
|
2月前
|
NoSQL Java Redis
太惨痛: Redis 分布式锁 5个大坑,又大又深, 如何才能 避开 ?
Redis分布式锁在高并发场景下是重要的技术手段,但其实现过程中常遇到五大深坑:**原子性问题**、**连接耗尽问题**、**锁过期问题**、**锁失效问题**以及**锁分段问题**。这些问题不仅影响系统的稳定性和性能,还可能导致数据不一致。尼恩在实际项目中总结了这些坑,并提供了详细的解决方案,包括使用Lua脚本保证原子性、设置合理的锁过期时间和使用看门狗机制、以及通过锁分段提升性能。这些经验和技巧对面试和实际开发都有很大帮助,值得深入学习和实践。
太惨痛: Redis 分布式锁 5个大坑,又大又深, 如何才能 避开 ?
|
24天前
|
存储 NoSQL Java
使用lock4j-redis-template-spring-boot-starter实现redis分布式锁
通过使用 `lock4j-redis-template-spring-boot-starter`,我们可以轻松实现 Redis 分布式锁,从而解决分布式系统中多个实例并发访问共享资源的问题。合理配置和使用分布式锁,可以有效提高系统的稳定性和数据的一致性。希望本文对你在实际项目中使用 Redis 分布式锁有所帮助。
70 5