springboot多数据源整合分布式事务

如何解决多数据源分包分布式事务

  • 多数据源分布式事务问题和真领域中产生的分布式事务问题是不一样的。
  • 多数据源分布式事务的问题产生在同一个项目中,有多个不同的数据库连接。
  • 分布式领域中的事务因为系统的拆分,每个服务都有自己独立的数据库。

多数据源项目中如何解决分布式事务问题

  • 使用springboot+jta+atomikos分布式事务管理:Atomikos 是一个为Java平台提供增值服务的并且开源类事务管理器。

分布式领域中的如何解决分布式事务问题

  • TX-LCN分布式事务框架
  • TCC分布式事务

  • 基于MQ解决分布式事务

多数据源怎么解决分布式事务?

pom.xml引入

  
        org.springframework.boot
        spring-boot-starter-parent
        2.0.0.RELEASE
    
    
        
            org.springframework.boot
            spring-boot-starter
        
        
        
            org.springframework.boot
            spring-boot-starter-test
            test
        
        
            org.mybatis.spring.boot
            mybatis-spring-boot-starter
            1.1.1
        
        
        
            mysql
            mysql-connector-java
        
        
        
            org.springframework.boot
            spring-boot-starter-web
        
        
        
            org.springframework.boot
            spring-boot-starter-jta-atomikos
        
  
        
            org.projectlombok
            lombok
            1.16.20
        
    

application.yml配置文件信息

###springboot2.0名称url在多数据源的情况下变成jdbc-url,否则出现debug
###准备两个数据库连接:mumber/order
spring:
  datasource:
    ##会员数据库连接
    member:
      url: jdbc:mysql://localhost:3306/user
      username: root
      password: 123123
      borrowConnectionTimeout: 30
      loginTimeout: 30
      maintenanceInterval: 60
      maxIdleTime: 60
      minPoolSize: 3
      maxPoolSize: 25
      maxLifetime: 20000
      uniqueResourceName: memberDatasource
      ##订单数据库连接
    order:
      url: jdbc:mysql://localhost:3306/order
      username: root
      password: 123123
      borrowConnectionTimeout: 30
      loginTimeout: 30
      maintenanceInterval: 60
      maxIdleTime: 60
      minPoolSize: 3
      maxPoolSize: 25
      maxLifetime: 20000
      uniqueResourceName: orderDatasource

创建两个配置文件MemberConfig.java

package com.xyt.springboot.config.member;

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

@Data
@ConfigurationProperties(prefix = "spring.datasource.member")
public class MemberConfig {
    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;

}

OrderConfig.java

package com.xyt.springboot.config.order;

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

@Data
@ConfigurationProperties(prefix = "spring.datasource.order")//记得在启动项目的时候开启@EnableConfigurationProperties({MemberConfig.class, OrderConfig.class})
public class OrderConfig {
    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;
}

spring容器注入配置文件代码

MemberDatasourceConfig.java

package com.xyt.springboot.config.member;

import com.mysql.jdbc.jdbc2.optional.MysqlXADataSource;
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.jta.atomikos.AtomikosDataSourceBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Primary;
import org.springframework.jdbc.datasource.DataSourceTransactionManager;

import javax.sql.DataSource;
import java.sql.SQLException;


@Configuration
@MapperScan(basePackages = "com.xyt.springboot.member.mapper", sqlSessionFactoryRef = "memberSqlSessionFactory")
public class MemberDatasourceConfig {
    /**
     * 创建我们的datasource
     *
     * @return
     */
    @Bean("memberDataSource")//spring容器注入
    public DataSource memberDataSource(MemberConfig memberConfig) {
        //1.创建xaDatasource
        MysqlXADataSource mysqlXaDataSource = new MysqlXADataSource();
        mysqlXaDataSource.setUrl(memberConfig.getUrl());
        mysqlXaDataSource.setPinGlobalTxToPhysicalConnection(true);
        mysqlXaDataSource.setPassword(memberConfig.getPassword());
        mysqlXaDataSource.setUser(memberConfig.getUsername());
        mysqlXaDataSource.setPinGlobalTxToPhysicalConnection(true);

        //注册到全局事务上
        AtomikosDataSourceBean xaDataSource = new AtomikosDataSourceBean();
        xaDataSource.setXaDataSource(mysqlXaDataSource);
        xaDataSource.setUniqueResourceName(memberConfig.getUniqueResourceName());
        xaDataSource.setMinPoolSize(memberConfig.getMinPoolSize());
        xaDataSource.setMaxPoolSize(memberConfig.getMaxPoolSize());
        xaDataSource.setMaxLifetime(memberConfig.getMaxLifetime());
        xaDataSource.setBorrowConnectionTimeout(memberConfig.getBorrowConnectionTimeout());
        try {
            xaDataSource.setLoginTimeout(memberConfig.getLoginTimeout());
        } catch (SQLException e) {
            e.printStackTrace();
        }
        xaDataSource.setMaintenanceInterval(memberConfig.getMaintenanceInterval());
        xaDataSource.setMaxIdleTime(memberConfig.getMaxIdleTime());
        xaDataSource.setTestQuery(memberConfig.getTestQuery());
        return xaDataSource;
    }

    @Bean(name = "memberSqlSessionFactory")
    public SqlSessionFactory memberSqlSessionFactory(@Qualifier("memberDataSource") DataSource dataSource)
            throws Exception {
        SqlSessionFactoryBean bean = new SqlSessionFactoryBean();
        bean.setDataSource(dataSource);//注入Datasource
        // bean.setMapperLocations(
        // new
        // PathMatchingResourcePatternResolver().getResources("classpath:mybatis/mapper/test2/*.xml"));
        return bean.getObject();
    }

//    /**
//     * 事务管理
//     *
//     * @param dataSource * @return
//     */
//    @Primary
//    @Bean(name = "memberTransactionManager")
//    public DataSourceTransactionManager memberTransactionManager(@Qualifier("memberDataSource") DataSource dataSource) {
//        return new DataSourceTransactionManager(dataSource);
//    }

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

OrderDatasourceConfig.java

package com.xyt.springboot.config.order;

import com.mysql.jdbc.jdbc2.optional.MysqlXADataSource;
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.boot.jta.atomikos.AtomikosDataSourceBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.jdbc.datasource.DataSourceTransactionManager;

import javax.sql.DataSource;
import java.sql.SQLException;

@Configuration//@Configuration等同于OrderDatasourceConfig.xml
@MapperScan(basePackages = "com.xyt.springboot.order.mapper", sqlSessionFactoryRef = "orderSqlSessionFactory")//com.xyt.springboot.order.mapper是mapper路径
public class OrderDatasourceConfig {

    /**
     * 创建我们的datasource
     *
     * @return
     */
    @Bean("orderDataSource")//spring容器注入
    public DataSource orderDataSource(OrderConfig orderConfig) {
        //1.创建xaDatasource
        MysqlXADataSource mysqlXaDataSource = new MysqlXADataSource();
        mysqlXaDataSource.setUrl(orderConfig.getUrl());
        mysqlXaDataSource.setPinGlobalTxToPhysicalConnection(true);
        mysqlXaDataSource.setPassword(orderConfig.getPassword());
        mysqlXaDataSource.setUser(orderConfig.getUsername());
        mysqlXaDataSource.setPinGlobalTxToPhysicalConnection(true);

        //注册到全局事务上
        AtomikosDataSourceBean xaDataSource = new AtomikosDataSourceBean();
        xaDataSource.setXaDataSource(mysqlXaDataSource);
        xaDataSource.setUniqueResourceName(orderConfig.getUniqueResourceName());
        xaDataSource.setMinPoolSize(orderConfig.getMinPoolSize());
        xaDataSource.setMaxPoolSize(orderConfig.getMaxPoolSize());
        xaDataSource.setMaxLifetime(orderConfig.getMaxLifetime());
        xaDataSource.setBorrowConnectionTimeout(orderConfig.getBorrowConnectionTimeout());
        try {
            xaDataSource.setLoginTimeout(orderConfig.getLoginTimeout());
        } catch (SQLException e) {
            e.printStackTrace();
        }
        xaDataSource.setMaintenanceInterval(orderConfig.getMaintenanceInterval());
        xaDataSource.setMaxIdleTime(orderConfig.getMaxIdleTime());
        xaDataSource.setTestQuery(orderConfig.getTestQuery());
        return xaDataSource;
    }

    @Bean(name = "orderSqlSessionFactory")
    public SqlSessionFactory orderSqlSessionFactory(@Qualifier("orderDataSource") DataSource dataSource)
            throws Exception {
        SqlSessionFactoryBean bean = new SqlSessionFactoryBean();
        bean.setDataSource(dataSource);
        // bean.setMapperLocations(
        // new
        // PathMatchingResourcePatternResolver().getResources("classpath:mybatis/mapper/test2/*.xml"));
        return bean.getObject();
    }

//    /**
//     * 事务管理
//     *
//     * @param dataSource
//     * @return
//     */
//    @Bean(name = "orderTransactionManager")
//    public DataSourceTransactionManager orderTransactionManager(@Qualifier("orderDataSource") DataSource dataSource) {
//        return new DataSourceTransactionManager(dataSource);
//    }

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

服务层代码Service

package com.xyt.springboot.service;

import com.xyt.springboot.member.mapper.UserMapper;
import com.xyt.springboot.order.mapper.OrderMapper;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

@Service
public class UserService {
    @Autowired
    private UserMapper userMapper;
    @Autowired
    private OrderMapper orderMapper;

    /**
     * 调用User数据库
     *
     * @param name
     * @param age
     * @return
     * @Transactional事务底层采用Aop技术 增强
     */
    @Transactional//开启事务
    public int addUser(String name, int age) {
        //操作会员数据库
        int i = userMapper.addUser(name, age);
        //操作订单数据库
        int b = orderMapper.addOrder(name);
        int j = 1 / age;
        return i;
    }

    /**
     * 调用Order数据库
     *
     * @param order_no
     * @return
     */
    public int addOrder(String order_no) {
        return orderMapper.addOrder(order_no);
    }
}

mapper代码

UserMaaper.java

package com.xyt.springboot.member.mapper;

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

public interface UserMapper {
	@Insert("insert into users values(null,#{name},#{age});")
	public int addUser(@Param("name") String name, @Param("age") Integer age);
}

OrderMapper.java

package com.xyt.springboot.order.mapper;

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

public interface OrderMapper {
    @Insert("insert into orders values(null,#{order_no});")
    public int addOrder(@Param("order_no") String order_no);
}

项目结构

springboot多数据源整合分布式事务_第1张图片

启动代码

package com.xyt.springboot;

import com.xyt.springboot.config.member.MemberConfig;
import com.xyt.springboot.config.member.MemberDatasourceConfig;
import com.xyt.springboot.config.order.OrderConfig;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.context.properties.EnableConfigurationProperties;

@SpringBootApplication
@MapperScan("com.xyt.springboot.mapper")
@EnableConfigurationProperties({MemberConfig.class, OrderConfig.class})//开启让@ConfigurationProperties生效
public class AppSpringBootMybatis {
    public static void main(String[] args) {
        SpringApplication.run(AppSpringBootMybatis.class, args);
    }
}

 

你可能感兴趣的:(Java,springBoot,Mysql)