SpringBoot多数据源与Atomikos分布式事务【SpringBoot+JTA+Atomikos】

1:pom.xml引入相关依赖jar

<!--springboot整合mybatis的依赖 -->
        <!-- https://mvnrepository.com/artifact/org.mybatis.spring.boot/mybatis-spring-boot-starter -->
        <dependency>
            <groupId>org.mybatis.spring.boot</groupId>
            <artifactId>mybatis-spring-boot-starter</artifactId>
            <version>2.1.4</version>
        </dependency>
        <!-- https://mvnrepository.com/artifact/mysql/mysql-connector-java -->
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>8.0.22</version>
        </dependency>
        <!-- https://mvnrepository.com/artifact/org.springframework.boot/spring-boot-starter-jta-atomikos -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-jta-atomikos</artifactId>
        </dependency>
        <!-- https://mvnrepository.com/artifact/org.projectlombok/lombok -->
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <version>1.18.16</version>
            <scope>provided</scope>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-configuration-processor</artifactId>
            <optional>true</optional>
        </dependency>

 

2、application.yml配置多数据源

spring:
  datasource:
    test1:
      url: jdbc:mysql://localhost:3306/test1?useUnicode=true&characterEncoding=utf-8&useSSL=false&serverTimezone=GMT&allowMultiQueries=true
      username: root
      password: root
      driver-class-name: com.mysql.cj.jdbc.Driver
      sql-script-encoding: UTF-8
      type: com.zaxxer.hikari.HikariDataSource
      initialization-mode: always
      continue-on-error: true
      hikari:
        minimum-idle: 5
        connection-test-query: SELECT 1 FROM DUAL
        maximum-pool-size: 20
        auto-commit: true
        idle-timeout: 30000
        pool-name: SpringBootDemoHikariCP
        max-lifetime: 60000
        connection-timeout: 30000
      logging:
        level:
          com.qjc.dao.Test1: TARCE
      borrowConnectionTimeout: 30
      loginTimeout: 30
      maintenanceInterval: 60
      maxIdleTime: 60
      maxLifetime: 20000
      maxPoolSize: 25
      minPoolSize: 3
      uniqueResourceName: test1
      testQuery: SELECT 1 FROM DUAL
    test2:
      url: jdbc:mysql://localhost:3306/test2?useUnicode=true&characterEncoding=utf-8&useSSL=false&serverTimezone=GMT&allowMultiQueries=true
      username: root
      password: root
      driver-class-name: com.mysql.cj.jdbc.Driver
      sql-script-encoding: UTF-8
      type: com.zaxxer.hikari.HikariDataSource
      initialization-mode: always
      continue-on-error: true
      hikari:
        minimum-idle: 5
        connection-test-query: SELECT 1 FROM DUAL
        maximum-pool-size: 20
        auto-commit: true
        idle-timeout: 30000
        pool-name: SpringBootDemoHikariCP
        max-lifetime: 60000
        connection-timeout: 30000
      logging:
        level:
         com.qjc.dao.Test2: TARCE
      borrowConnectionTimeout: 30
      loginTimeout: 30
      maintenanceInterval: 60
      maxIdleTime: 60
      maxLifetime: 20000
      maxPoolSize: 25
      minPoolSize: 3
      uniqueResourceName: test2
      testQuery: SELECT 1 FROM DUAL

3、具体数据源的config和application.yml配置的数据源对应

package com.example.config;

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

import lombok.Data;

@Data
@ConfigurationProperties(prefix = "spring.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;
    private String uniqueResourceName;
}
package com.example.config;

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

import lombok.Data;

@Data
@ConfigurationProperties(prefix = "spring.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;
    private String uniqueResourceName;
}

4、启动类上加具体数据源的config

package com.example;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.context.properties.EnableConfigurationProperties;

import com.example.config.DBConfig1;
import com.example.config.DBConfig2;

@SpringBootApplication
@EnableConfigurationProperties({DBConfig1.class, DBConfig2.class})
public class App {

    public static void main(String[] args) {
        SpringApplication.run(App.class, args);
    }
}

5、配置数据源加事务配置

package com.example.config;

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.mysql.cj.jdbc.MysqlXADataSource;

@Configuration
//basePackages 最好分开配置,放在同一个文件夹可能会报错
@MapperScan(basePackages = {"com.example.mapper.test1"},sqlSessionTemplateRef = "test1SqlSessionTemplate")
public class DataSourceConfig1 {
    /**
     * 配置数据源
     * @return
     */
    @Primary
    @Bean("test1DataSource")
    public DataSource e3shopDataSource(DBConfig1 eBConfig1) throws SQLException {
        //创建xa datasource
        MysqlXADataSource mysqlXADataSource=new MysqlXADataSource();
        mysqlXADataSource.setUrl(eBConfig1.getUrl());
        mysqlXADataSource.setPinGlobalTxToPhysicalConnection(true);
        mysqlXADataSource.setPassword(eBConfig1.getPassWord());
        mysqlXADataSource.setUser(eBConfig1.getUserName());
        mysqlXADataSource.setPinGlobalTxToPhysicalConnection(true);

        //2.注册到我们全局事务上
        AtomikosDataSourceBean xaDataSource =new AtomikosDataSourceBean();
        xaDataSource.setXaDataSource(mysqlXADataSource);
        xaDataSource.setUniqueResourceName(eBConfig1.getUniqueResourceName());
        xaDataSource.setMinPoolSize(eBConfig1.getMinPoolSize());
        xaDataSource.setMaxPoolSize(eBConfig1.getMaxPoolSize());
        xaDataSource.setBorrowConnectionTimeout(eBConfig1.getBorrowConnectionTimeout());
        xaDataSource.setLoginTimeout(eBConfig1.getLoginTimeout());
        xaDataSource.setMaintenanceInterval(eBConfig1.getMaintenanceInterval());
        xaDataSource.setMaxIdleTime(eBConfig1.getMaxIdleTime());
        xaDataSource.setTestQuery(eBConfig1.getTestQuery());
        return xaDataSource;

    }
    /**
     * sqlSessionFactory
     * @param dataSource
     * @return
     * @throws Exception
     */
    @Primary
    @Bean("test1SqlSessionFactory")
    public SqlSessionFactory e3shopSqlSessionFactory(@Qualifier("test1DataSource") DataSource dataSource) throws Exception {
        SqlSessionFactoryBean sqlSessionFactoryBean = new SqlSessionFactoryBean();
        sqlSessionFactoryBean.setDataSource(dataSource);
        return sqlSessionFactoryBean.getObject();
    }

    /**
     * sqlsessionTemplate
     * @param sqlSessionFactory
     * @return
     */
    @Primary
    @Bean(name = "test1SqlSessionTemplate")
    public SqlSessionTemplate e3shopSqlSessionTemplate(@Qualifier("test1SqlSessionFactory") SqlSessionFactory sqlSessionFactory) {
        return new SqlSessionTemplate(sqlSessionFactory);
    }
}
package com.example.config;

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.cj.jdbc.MysqlXADataSource;

@Configuration
//basePackages 最好分开配置,放在同一个文件夹可能会报错
@MapperScan(basePackages = {"com.example.mapper.test2"},sqlSessionTemplateRef = "test2SqlSessionTemplate")
public class DataSourceConfig2 {
    /**
     * 配置数据源
     * @return
     */
    @Bean("test2DataSource")
    public DataSource e3shopDataSource(DBConfig2 eBConfig1) throws SQLException {
        //创建xa datasource
        MysqlXADataSource mysqlXADataSource=new MysqlXADataSource();
        mysqlXADataSource.setUrl(eBConfig1.getUrl());
        mysqlXADataSource.setPinGlobalTxToPhysicalConnection(true);
        mysqlXADataSource.setPassword(eBConfig1.getPassWord());
        mysqlXADataSource.setUser(eBConfig1.getUserName());
        mysqlXADataSource.setPinGlobalTxToPhysicalConnection(true);

        //2.注册到我们全局事务上
        AtomikosDataSourceBean xaDataSource =new AtomikosDataSourceBean();
        xaDataSource.setXaDataSource(mysqlXADataSource);
        xaDataSource.setUniqueResourceName(eBConfig1.getUniqueResourceName());
        xaDataSource.setMinPoolSize(eBConfig1.getMinPoolSize());
        xaDataSource.setMaxPoolSize(eBConfig1.getMaxPoolSize());
        xaDataSource.setBorrowConnectionTimeout(eBConfig1.getBorrowConnectionTimeout());
        xaDataSource.setLoginTimeout(eBConfig1.getLoginTimeout());
        xaDataSource.setMaintenanceInterval(eBConfig1.getMaintenanceInterval());
        xaDataSource.setMaxIdleTime(eBConfig1.getMaxIdleTime());
        xaDataSource.setTestQuery(eBConfig1.getTestQuery());
        return xaDataSource;

    }
    /**
     * sqlSessionFactory
     * @param dataSource
     * @return
     * @throws Exception
     */
    @Bean("test2SqlSessionFactory")
    public SqlSessionFactory e3shopSqlSessionFactory(@Qualifier("test2DataSource") DataSource dataSource) throws Exception {
        SqlSessionFactoryBean sqlSessionFactoryBean = new SqlSessionFactoryBean();
        sqlSessionFactoryBean.setDataSource(dataSource);
        return sqlSessionFactoryBean.getObject();
    }

    /**
     * sqlsessionTemplate
     * @param sqlSessionFactory
     * @return
     */
    @Bean(name = "test2SqlSessionTemplate")
    public SqlSessionTemplate e3shopSqlSessionTemplate(@Qualifier("test2SqlSessionFactory") SqlSessionFactory sqlSessionFactory) {
        return new SqlSessionTemplate(sqlSessionFactory);
    }
}

6、添加mapper层操作数据库

package com.example.mapper.test1;

import org.apache.ibatis.annotations.Insert;
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Param;

@Mapper
public interface User1Mapper {
    @Insert("INSERT INTO user (username, sex, password) VALUES ( #{username}, #{sex}, #{password})")
    int insertUser(@Param("username")String username,@Param("sex")String  sex,@Param("password")String password);
}
package com.example.mapper.test2;

import org.apache.ibatis.annotations.Insert;
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Param;

@Mapper
public interface User2Mapper {
    @Insert("INSERT INTO user (username, sex, password) VALUES ( #{username}, #{sex}, #{password})")
    int insertUser(@Param("username")String username,@Param("sex")String  sex,@Param("password")String password);
}

7、service层添加事务@Transactional

package com.example.service.impl;

import javax.transaction.Transactional;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import com.example.mapper.test1.User1Mapper;
import com.example.mapper.test2.User2Mapper;
import com.example.service.UserService;
@Service
public class UserServiceImpl implements UserService {
    
    @Autowired
    private User1Mapper user1Mapper;
    @Autowired
    private User2Mapper user2Mapper;
    @Transactional
    @Override
    public int addUser(String username, String sex, String password) {
        int rtu1=user1Mapper.insertUser(username, sex, password);
        int rtu2=user2Mapper.insertUser(username, sex, password);
        return rtu1+rtu2;
    }

}

完成,剩余的就是Controller层调用了

posted @ 2021-01-09 16:46  hzy_叶子  阅读(1013)  评论(0编辑  收藏  举报