springboot整合atomikos实践—单体项目多数据源整合

springboot整合atomikos—单体项目多数据源整合

最近管理后台增加了其他数据库的一些操作,如果只是简单的切换数据源的话使用动态数据源就可以实现,但动态数据源切换容易,加上事务处理就非常麻烦,seata是分布式事务的解决方案,管理后台一个单体服务也用不了,手动写事务处理又非常麻烦,所以这里用了atomikos做多数据源的整合方案。
这里只做代码展示,原理这块无外乎XA协议,这块可以看mysql的知识梳理中对事务的讲解。

注意点:每个数据源要配置单独的dao package和xml。

一、引入atomikos jar包

<parent>
    <artifactId>spring-boot-starter-parent</artifactId>
    <groupId>org.springframework.boot</groupId>
    <version>2.0.6.RELEASE</version>
</parent>
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-jta-atomikos</artifactId>
</dependency>

二、配置文件中配置数据源连接信息

spring:
  datasource:
    db1:
      driver-class-name: com.mysql.jdbc.Driver
      url: jdbc:mysql://localhost:3306/db1?characterEncoding=utf-8&autoReconnect=true&failOverReadOnly=false
      username: root
      password: root
    db2:
      driver-class-name: com.mysql.jdbc.Driver
      url: jdbc:mysql://localhost:3306/db2?characterEncoding=utf-8&autoReconnect=true&failOverReadOnly=false
      username: root
      password: root
    db3:
      driver-class-name: com.mysql.jdbc.Driver
      url: jdbc:mysql://localhost:3306/db3?characterEncoding=utf-8&autoReconnect=true&failOverReadOnly=false
      username: root
      password: root

三、准备数据源配置文件

要注意一定要配置MapperScan,扫描每个数据库对应的dao和xml。

同样的配置,每个数据源配置一份。

在这里插入图片描述
在这里插入图片描述

import com.baomidou.mybatisplus.annotation.DbType;
import com.baomidou.mybatisplus.extension.plugins.MybatisPlusInterceptor;
import com.baomidou.mybatisplus.extension.plugins.inner.PaginationInnerInterceptor;
import com.baomidou.mybatisplus.extension.spring.MybatisSqlSessionFactoryBean;
import com.mysql.jdbc.jdbc2.optional.MysqlXADataSource;
import org.apache.ibatis.plugin.Interceptor;
import org.apache.ibatis.session.SqlSessionFactory;
import org.mybatis.spring.SqlSessionTemplate;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.jta.atomikos.AtomikosDataSourceBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.io.Resource;
import org.springframework.core.io.support.PathMatchingResourcePatternResolver;

import javax.sql.DataSource;


@Configuration
@MapperScan(basePackages = "com.comm.dao.db1", sqlSessionFactoryRef = "db1SqlSessionFactory")
public class Db1DatabaseConfig {
    @Value("${spring.datasource.db1.driver-class-name}")
    private String driverClassName;
    @Value("${spring.datasource.db1.url}")
    private String url;
    @Value("${spring.datasource.db1.username}")
    private String username;
    @Value("${spring.datasource.db1.password}")
    private String password;


    @Bean(name = "db1DataSource")
    public DataSource dataSource() {

        MysqlXADataSource mysqlXADataSource = new MysqlXADataSource();
        mysqlXADataSource.setUrl(url);
        mysqlXADataSource.setUser(username);
        mysqlXADataSource.setPassword(password);
        mysqlXADataSource.setPinGlobalTxToPhysicalConnection(true);

        AtomikosDataSourceBean xaDataSource = new AtomikosDataSourceBean();
        xaDataSource.setXaDataSource(mysqlXADataSource);
        xaDataSource.setUniqueResourceName("db1DataSource");
        xaDataSource.setMaxPoolSize(20);
        xaDataSource.setMinPoolSize(3);
        return xaDataSource;
    }


    //配置数据源
    @Bean(name = "db1SqlSessionFactory")
    public SqlSessionFactory db1SqlSessionFactory(@Qualifier("db1DataSource") DataSource dataSource) throws Exception {
        MybatisSqlSessionFactoryBean factoryBean = new MybatisSqlSessionFactoryBean();
        PathMatchingResourcePatternResolver pathMatchingResourcePatternResolver = new PathMatchingResourcePatternResolver();
        //mapper.xml 的位置
        Resource[] resources = pathMatchingResourcePatternResolver.getResources("classpath*:mybatis-mapper/db1/*.xml");
        factoryBean.setMapperLocations(resources);
        factoryBean.setDataSource(dataSource);
        //防止pagehelper分页功能失效
        MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();
        interceptor.addInnerInterceptor(new PaginationInnerInterceptor(DbType.MYSQL));
        factoryBean.setPlugins(new Interceptor[]{interceptor});
        return factoryBean.getObject();
    }

    @Bean(name = "db1SqlSessionTemplate")
    public SqlSessionTemplate db1SqlSessionTemplate(@Qualifier("db1SqlSessionFactory") SqlSessionFactory sqlSessionFactory) throws Exception {
        return new SqlSessionTemplate(sqlSessionFactory);
    }

}

四、准备transactionManager

import com.atomikos.icatch.jta.UserTransactionImp;
import com.atomikos.icatch.jta.UserTransactionManager;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.DependsOn;
import org.springframework.transaction.PlatformTransactionManager;
import org.springframework.transaction.jta.JtaTransactionManager;

import javax.transaction.TransactionManager;
import javax.transaction.UserTransaction;

@Configuration
public class TransactionManagerConfig {

    /**
     * 不管有多少个数据源只要配置一个 TransactionManager
     */

    @Bean(name = "atomikosTransactionManager")
    public TransactionManager atomikosTransactionManager(){
        UserTransactionManager userTransactionManager = new UserTransactionManager();
        userTransactionManager.setForceShutdown(false);
        return userTransactionManager;
    }

    @Bean(name = "transactionManager")
    @DependsOn({"userTransaction", "atomikosTransactionManager"})
    public PlatformTransactionManager transactionManager() throws Throwable {
        UserTransaction userTransaction = userTransaction();
        TransactionManager atomikosTransactionManager = atomikosTransactionManager();
        return new JtaTransactionManager(userTransaction, atomikosTransactionManager);
    }

    @Bean(name = "userTransaction")
    public UserTransaction userTransaction() throws Throwable {
        UserTransactionImp userTransactionImp = new UserTransactionImp();
        userTransactionImp.setTransactionTimeout(10000);
        return userTransactionImp;
    }


}

五、启动使用

和正常方法一样,在方法上加上@Transactional注解即可。不再演示了,atomikos的好处就是让你使用起来和单体服务中单个数据源一样,而且不用去额外搭建TM和注册中心等。

USING: com.atomikos.icatch.default_max_wait_time_on_shutdown = 922337203685477
USING: com.atomikos.icatch.allow_subtransactions = true
USING: com.atomikos.icatch.recovery_delay = 10000
USING: com.atomikos.icatch.automatic_resource_registration = true
USING: com.atomikos.icatch.oltp_max_retries = 5
USING: com.atomikos.icatch.client_demarcation = false
USING: com.atomikos.icatch.threaded_2pc = false
USING: com.atomikos.icatch.serial_jta_transactions = true
USING: com.atomikos.icatch.log_base_dir = ./
USING: com.atomikos.icatch.rmi_export_class = none
USING: com.atomikos.icatch.max_actives = 50
USING: com.atomikos.icatch.checkpoint_interval = 500
USING: com.atomikos.icatch.enable_logging = true
USING: com.atomikos.icatch.log_base_name = tmlog
USING: com.atomikos.icatch.max_timeout = 300000
USING: com.atomikos.icatch.trust_client_tm = false
USING: java.naming.factory.initial = com.sun.jndi.rmi.registry.RegistryContext
USING: com.atomikos.icatch.tm_unique_name = 172.17.170.113.tm
USING: com.atomikos.icatch.forget_orphaned_log_entries_delay = 86400000
USING: com.atomikos.icatch.oltp_retry_interval = 10000
USING: java.naming.provider.url = rmi://localhost:1099
USING: com.atomikos.icatch.force_shutdown_on_vm_exit = false
USING: com.atomikos.icatch.default_jta_timeout = 10000
Using default (local) logging and recovery...
db1DataSource: refreshed XAResource
db2DataSource: refreshed XAResource
db3DataSource: refreshed XAResource
022.06.17 16:00:43.388 INFO  org.springframework.transaction.jta.JtaTransactionManager 501 checkUserTransactionAndTransactionManager - Using JTA UserTransaction: com.atomikos.icatch.jta.UserTransactionImp@668a32a4
2022.06.17 16:00:43.389 INFO  org.springframework.transaction.jta.JtaTransactionManager 512 checkUserTransactionAndTransactionManager - Using JTA TransactionManager: com.atomikos.icatch.jta.UserTransactionManager@23b71d24
…………
Tomcat started on port(s): 9680 (http) with context path ''    
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值