springcloud alibaba mybatis-plus多数据源集成seata分布式事务

注意:这里不讲解seata的搭建 

这里使用的是默认的AT模式

1、加依赖

<cloud-alibaba.version>2021.0.4.0</cloud-alibaba.version>
<io.seata.version>1.6.1</io.seata.version>
<mybatis.plus.version>3.5.2</mybatis.plus.version> 
<!--seata-->
        <dependency>
            <groupId>io.seata</groupId>
            <artifactId>seata-spring-boot-starter</artifactId>
            <version>${io.seata.version}</version>
            <exclusions>
                <exclusion>
                    <artifactId>druid</artifactId>
                    <groupId>com.alibaba</groupId>
                </exclusion>
            </exclusions>
        </dependency>
        <dependency>
            <groupId>com.alibaba.cloud</groupId>
            <artifactId>spring-cloud-starter-alibaba-seata</artifactId>
            <version>${cloud-alibaba.version}</version>
            <exclusions>
                <exclusion>
                    <groupId>io.seata</groupId>
                    <artifactId>seata-spring-boot-starter</artifactId>
                </exclusion>
            </exclusions>
        </dependency>

 <!--mybatis-plus-->
    <dependency>
            <groupId>com.baomidou</groupId>
            <artifactId>mybatis-plus-boot-starter</artifactId>
            <version>${mybatis.plus.version}</version>
        </dependency>

2、加配置

A项目mybatis+seata配置

yml:

spring:
  application:
    name: A模块名称
    description: A模块描述
  datasource:
      orderdb:
        jdbc-url: jdbc:mysql://127.0.0.1:3306/A?useUnicode=true&characterEncoding=UTF-8&useSSL=false&serverTimezone=UTC
        username: A库
        password: 123456
        driver-class-name: com.mysql.jdbc.Driver
      funddatadb:
        jdbc-url: jdbc:mysql://127.0.0.1:3306/B?useUnicode=true&characterEncoding=UTF-8&useSSL=false&serverTimezone=UTC
        username: B库
        password: 123456
        driver-class-name: com.mysql.jdbc.Driver




#seata配置
seata:
  enabled: true
  enable-auto-data-source-proxy: true
  application-id: seata-cilent-deme
  # Seata 事务组编号,此处需于 seata 相同
  tx-service-group: default-tx-group
  data-source-proxy-mode: AT
  config:
    type: nacos
    nacos:
      # nacos ip地址
      server-addr: nacos地址
      group: DEFAULT_GROUP
      data-id: seata-server.properties # 读取 nacos seata 配置
      namespace: nacos命名空间
      username: nacos账号
      password: nacos密码
  registry:
    type: nacos
    nacos:
      application: seata-server # seata 服务名
      # nacos ip地址
      server-addr:  nacos地址
      group: DEFAULT_GROUP
      namespace: nacos命名空间
      username: nacos账号
      password: nacos密码


 nacos对应的seata-server.properties 配置

service.vgroupMapping.default-tx-group=default
service.enableDegrade=false
service.disableGlobalTransaction=false

#Transaction storage configuration, only for the server. The file, DB, and redis configuration values are optional.
store.mode=db
store.lock.mode=db
store.session.mode=db
#Used for password encryption
store.publicKey=

#These configurations are required if the `store mode` is `db`. If `store.mode,store.lock.mode,store.session.mode` are not equal to `db`, you can remove the configuration block.
store.db.datasource=druid
store.db.dbType=mysql
store.db.driverClassName=com.mysql.cj.jdbc.Driver
store.db.url=jdbc:mysql://127.0.0.1:3306/seata?useUnicode=true&rewriteBatchedStatements=true
store.db.user=seata
store.db.password=123456
store.db.minConn=5
store.db.maxConn=30
store.db.globalTable=global_table
store.db.branchTable=branch_table
store.db.distributedLockTable=distributed_lock
store.db.queryLimit=100
store.db.lockTable=lock_table
store.db.maxWait=5000

#Transaction rule configuration, only for the server
server.recovery.committingRetryPeriod=1000
server.recovery.asynCommittingRetryPeriod=1000
server.recovery.rollbackingRetryPeriod=1000
server.recovery.timeoutRetryPeriod=1000
server.maxCommitRetryTimeout=-1
server.maxRollbackRetryTimeout=-1
server.rollbackRetryTimeoutUnlockEnable=false
server.distributedLockExpireTime=10000
server.xaerNotaRetryTimeout=60000
server.session.branchAsyncQueueSize=5000
server.session.enableBranchAsyncRemove=false

#Transaction rule configuration, only for the client
client.rm.asyncCommitBufferLimit=10000
client.rm.lock.retryInterval=10
client.rm.lock.retryTimes=30
client.rm.lock.retryPolicyBranchRollbackOnConflict=true
client.rm.reportRetryCount=5
client.rm.tableMetaCheckEnable=true
client.rm.tableMetaCheckerInterval=60000
client.rm.sqlParserType=druid
client.rm.reportSuccessEnable=false
client.rm.sagaBranchRegisterEnable=false
client.rm.sagaJsonParser=fastjson
client.rm.tccActionInterceptorOrder=-2147482648
client.tm.commitRetryCount=5
client.tm.rollbackRetryCount=5
client.tm.defaultGlobalTransactionTimeout=60000
client.tm.degradeCheck=false
client.tm.degradeCheckAllowTimes=10
client.tm.degradeCheckPeriod=2000
client.tm.interceptorOrder=-2147482648
client.undo.dataValidation=true
client.undo.logSerialization=jackson
client.undo.onlyCareUpdateColumns=true
server.undo.logSaveDays=7
server.undo.logDeletePeriod=86400000
client.undo.logTable=undo_log
client.undo.compress.enable=true
client.undo.compress.type=zip
client.undo.compress.threshold=64k

#For TCC transaction mode
tcc.fence.logTableName=tcc_fence_log
tcc.fence.cleanPeriod=1h

#Log rule configuration, for client and server
log.exceptionRate=100
#Metrics configuration, only for the server
metrics.enabled=false
metrics.registryType=compact
metrics.exporterList=prometheus
metrics.exporterPrometheusPort=9898
#For details about configuration items, see https://seata.io/zh-cn/docs/user/configurations.html
#Transport configuration, for client and server
transport.type=TCP
transport.server=NIO
transport.heartbeat=true
transport.enableTmClientBatchSendRequest=false
transport.enableRmClientBatchSendRequest=true
transport.enableTcServerBatchSendResponse=false
transport.rpcRmRequestTimeout=30000
transport.rpcTmRequestTimeout=30000
transport.rpcTcRequestTimeout=30000
transport.threadFactory.bossThreadPrefix=NettyBoss
transport.threadFactory.workerThreadPrefix=NettyServerNIOWorker
transport.threadFactory.serverExecutorThreadPrefix=NettyServerBizHandler
transport.threadFactory.shareBossWorker=false
transport.threadFactory.clientSelectorThreadPrefix=NettyClientSelector
transport.threadFactory.clientSelectorThreadSize=1
transport.threadFactory.clientWorkerThreadPrefix=NettyClientWorkerThread
transport.threadFactory.bossThreadSize=1
transport.threadFactory.workerThreadSize=default
transport.shutdown.wait=3
transport.serialization=seata
transport.compressor=none

在所需要分布式事务的库创建undo_log表 每个数据源库都需要

CREATE TABLE `undo_log` (
  `id` bigint(20) NOT NULL AUTO_INCREMENT,
  `branch_id` bigint(20) NOT NULL COMMENT 'branch transaction id',
  `xid` varchar(100) NOT NULL COMMENT 'global transaction id',
  `context` varchar(128) NOT NULL COMMENT 'undo_log context,such as serialization',
  `rollback_info` longblob NOT NULL COMMENT 'rollback info',
  `log_status` int(11) NOT NULL COMMENT '0:normal status,1:defense status',
  `log_created` datetime(6) NOT NULL COMMENT 'create datetime',
  `log_modified` datetime(6) NOT NULL COMMENT 'modify datetime',
  PRIMARY KEY (`id`),
  UNIQUE KEY `ux_undo_log` (`xid`,`branch_id`)
) ENGINE=InnoDB AUTO_INCREMENT=25 DEFAULT CHARSET=utf8mb4 COMMENT='AT transaction mode undo table';

B项目:同A项目mybatis+seata配置

........此处同A项目配置

A项目Mybatis配置:

DataSourceOrderConfig


import com.zaxxer.hikari.HikariDataSource;
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.context.annotation.Primary;
import org.springframework.core.annotation.Order;

import javax.sql.DataSource;
import java.util.HashMap;
import java.util.Map;

@Order(5)
@Configuration
public class DataSourceOrderConfig {
   // @Primary
    @Bean(name = "orderDataSource")
    @ConfigurationProperties("spring.datasource.orderdb")
    public DataSource orderDataSource() {
        return DataSourceBuilder.create().type(HikariDataSource.class).build();
    }
   // @Primary
    @Bean(name = "funddataDataSource")
    @ConfigurationProperties("spring.datasource.funddatadb")
    public DataSource funddataDataSource() {
        return DataSourceBuilder.create().type(HikariDataSource.class).build();
    }

MybatisFundDataConfig

import com.baomidou.mybatisplus.core.MybatisConfiguration;
import com.baomidou.mybatisplus.extension.spring.MybatisSqlSessionFactoryBean;
import com.zaxxer.hikari.HikariDataSource;
import io.seata.rm.datasource.DataSourceProxy;
import org.apache.ibatis.logging.stdout.StdOutImpl;
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.context.annotation.Primary;
import org.springframework.core.annotation.Order;
import org.springframework.core.io.support.PathMatchingResourcePatternResolver;
import org.springframework.jdbc.datasource.DataSourceTransactionManager;

import javax.sql.DataSource;


@Order(6)
@Configuration
@MapperScan(basePackages = {"com.hy.hyproduct.mapper.funddata"},sqlSessionTemplateRef  = "funddataSqlSessionTemplate")
public class MybatisFundDataConfig {

    @Bean(name = "funddataTransactionManager")
    //@Primary
    public DataSourceTransactionManager setTransactionManager(@Qualifier("funddataDataSource") DataSource dataSource) {
        return new DataSourceTransactionManager(dataSource);
    }

    @Bean(name = "funddataDataSourceProxy")
    public DataSourceProxy funddataDataSourceProxy(@Qualifier("funddataDataSource") DataSource dataSource) {
        return new DataSourceProxy(dataSource);
    }
    @Bean(name = "funddataSqlSessionFactory")
    //@Primary
    public SqlSessionFactory setSqlSessionFactory(@Qualifier("funddataDataSourceProxy") DataSource dataSource) throws Exception {
        MybatisSqlSessionFactoryBean bean = new MybatisSqlSessionFactoryBean();
        bean.setDataSource(dataSource);
        // 分页插件配置
       /* PaginationInnerInterceptor paginationInterceptor = new PaginationInnerInterceptor();
        bean.setPlugins(new Interceptor[]{paginationInterceptor});*/

        // 配置打印sql语句
        MybatisConfiguration configuration = new MybatisConfiguration();
        //configuration.setLogImpl(StdOutImpl.class);
        //开启驼峰命名
        configuration.setMapUnderscoreToCamelCase(true);
        bean.setConfiguration(configuration);
        bean.setMapperLocations(new PathMatchingResourcePatternResolver().getResources("classpath:mapper/funddata/**/*.xml"));
        return bean.getObject();
    }

    @Bean(name = "funddataSqlSessionTemplate")
    @Primary
    public SqlSessionTemplate setSqlSessionTemplate(@Qualifier("funddataSqlSessionFactory") SqlSessionFactory sqlSessionFactory) throws Exception {
        return new SqlSessionTemplate(sqlSessionFactory);
    }
}
MybatisSaleOrderConfig

import com.baomidou.mybatisplus.core.MybatisConfiguration;
import com.baomidou.mybatisplus.extension.spring.MybatisSqlSessionFactoryBean;
import com.zaxxer.hikari.HikariDataSource;
import io.seata.rm.datasource.DataSourceProxy;
import org.apache.ibatis.logging.stdout.StdOutImpl;
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.context.annotation.Primary;
import org.springframework.core.annotation.Order;
import org.springframework.core.io.support.PathMatchingResourcePatternResolver;
import org.springframework.jdbc.datasource.DataSourceTransactionManager;

import javax.sql.DataSource;

@Order(6)
@Configuration
@MapperScan(basePackages = {"com.hy.hyproduct.mapper.funddata"},sqlSessionTemplateRef  = "funddataSqlSessionTemplate")
public class MybatisFundDataConfig {

    @Bean(name = "funddataTransactionManager")
    //@Primary
    public DataSourceTransactionManager setTransactionManager(@Qualifier("funddataDataSource") DataSource dataSource) {
        return new DataSourceTransactionManager(dataSource);
    }

    @Bean(name = "funddataDataSourceProxy")
    public DataSourceProxy funddataDataSourceProxy(@Qualifier("funddataDataSource") DataSource dataSource) {
        return new DataSourceProxy(dataSource);
    }
    @Bean(name = "funddataSqlSessionFactory")
    //@Primary
    public SqlSessionFactory setSqlSessionFactory(@Qualifier("funddataDataSourceProxy") DataSource dataSource) throws Exception {
        MybatisSqlSessionFactoryBean bean = new MybatisSqlSessionFactoryBean();
        bean.setDataSource(dataSource);
        // 分页插件配置
       /* PaginationInnerInterceptor paginationInterceptor = new PaginationInnerInterceptor();
        bean.setPlugins(new Interceptor[]{paginationInterceptor});*/

        // 配置打印sql语句
        MybatisConfiguration configuration = new MybatisConfiguration();
        //configuration.setLogImpl(StdOutImpl.class);
        //开启驼峰命名
        configuration.setMapUnderscoreToCamelCase(true);
        bean.setConfiguration(configuration);
        bean.setMapperLocations(new PathMatchingResourcePatternResolver().getResources("classpath:mapper/funddata/**/*.xml"));
        return bean.getObject();
    }

    @Bean(name = "funddataSqlSessionTemplate")
    @Primary
    public SqlSessionTemplate setSqlSessionTemplate(@Qualifier("funddataSqlSessionFactory") SqlSessionFactory sqlSessionFactory) throws Exception {
        return new SqlSessionTemplate(sqlSessionFactory);
    }
}

B项目mybatis同A项目这里省略.......

注意以上mybatis集成seata主要是把数据源给了seata的代理类DataSourceProxy 

最后在2边的方法上面加上@GlobalTransactional注解就行了

以上代码是博主进行试验过的,可以成功退回

AT模式原理具体参考这篇文章:https://blog.csdn.net/qq_48721706/article/details/122656490

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 3
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值