0


shardingsphere分库分表集成多数据源

如果有分库分表,又有切换数据源的需求可以使用多数据源dynamic-datasource与shardingsphere集成的场景方案。

1、pom.xml添加maven依赖

<!-- ShardingSphere 读写分离/分库分表 -->
<dependency>
  <groupId>org.apache.shardingsphere</groupId>
  <artifactId>shardingsphere-jdbc-core-spring-boot-starter</artifactId>
  <version>5.1.2</version>
</dependency>

2、分别配置shardingjdbc和多数据源 yaml配置 同Nacos配置

# spring配置
spring: 
  redis:
    host: localhost
    port: 6379
    password: 
  # 分库分表配置
  shardingsphere:
    datasource:
      ds0:
        driver-class-name: com.mysql.cj.jdbc.Driver
        type: com.zaxxer.hikari.HikariDataSource
        username: root
        password: password
        jdbc-url: jdbc:mysql://localhost:3306/yz-log?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=true&serverTimezone=GMT%2B8
      names: ds0
    props:
      sql-show: true
    rules:
      sharding:            #根据http请求进行分表存储
        sharding-algorithms:
          table-inline:
            props:
              algorithm-expression: oper_log_$->{request_method}
            type: INLINE
        tables:
          oper_log:
            actual-data-nodes: ds0.oper_log_GET,ds0.oper_log_POST,ds0.oper_log_PUT,ds0.oper_log_DELETE
            table-strategy:
              standard:
                sharding-algorithm-name: table-inline
                sharding-column: request_method
    # 动态数据源配置
  datasource:
    dynamic:
      datasource:
        master:        #数据源1
          username: root
          password: password
          url: jdbc:mysql://localhost:3306/yz_cloud?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=true&serverTimezone=GMT%2B8
          driver-class-name: com.mysql.cj.jdbc.Driver
        order:        #数据源2
          username: root
          password: password
          url: jdbc:mysql://localhost:3306/yz_order?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=true&serverTimezone=GMT%2B8
          driver-class-name: com.mysql.cj.jdbc.Driver

3、添加一个多数据测试库yz-order和表sys_order

DROP DATABASE IF EXISTS `yz_order`;

CREATE DATABASE  `yz_order` DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci;

SET NAMES utf8mb4;
SET FOREIGN_KEY_CHECKS = 0;

USE `yz_order`;

-- ----------------------------
-- 订单信息表sys_order
-- ----------------------------
DROP TABLE IF EXISTS sys_order;
CREATE TABLE sys_order
(
  order_id      BIGINT(20)      NOT NULL AUTO_INCREMENT    COMMENT '订单ID',
  user_id       BIGINT(64)      NOT NULL                   COMMENT '用户编号',
  STATUS        CHAR(1)         NOT NULL                   COMMENT '状态(0交易成功 1交易失败)',
  order_no      VARCHAR(64)     DEFAULT NULL               COMMENT '订单流水',
  PRIMARY KEY (order_id)
) ENGINE=INNODB COMMENT = '订单信息表';

4、添加sys_order测试代码

SysOrder.java

/**
 * 订单对象 tb_order
 * 
 * @author yz
 */
public class SysOrder extends BaseEntity
{
    private static final long serialVersionUID = 1L;

    /** 订单编号 */
    private Long orderId;

    /** 用户编号 */
    private Long userId;

    /** 状态 */
    private String status;

    /** 订单编号 */
    private String orderNo;

}

省略SysOrderMapper.java

省略ISysOrderService.java

以下SysOrderServiceImpl.java

/**
 * 订单Service业务层处理
 * 
 * @author yz
 */
@Service
public class SysOrderServiceImpl implements ISysOrderService
{
    @Autowired
    private SysOrderMapper myShardingMapper;

    /**
     * 查询订单
     * 
     * @param orderId 订单编号
     * @return 订单信息
     */
    @Override
    @DS("order")
    public SysOrder selectSysOrderById(Long orderId)
    {
        return myShardingMapper.selectSysOrderById(orderId);
    }

    /**
     * 查询订单列表
     * 
     * @param sysOrder 订单信息
     * @return 订单列表
     */
    @Override
    @DS("order")
    public List<SysOrder> selectSysOrderList(SysOrder sysOrder)
    {
        return myShardingMapper.selectSysOrderList(sysOrder);
    }

    /**
     * 新增订单
     * 
     * @param sysOrder 订单
     * @return 结果
     */
    @Override
    @DS("order")
    public int insertSysOrder(SysOrder sysOrder)
    {
        return myShardingMapper.insertSysOrder(sysOrder);
    }
}

@DS("order")切换数据源 为了不迷糊请看以下

   # 动态多数据源配置
  datasource:
    dynamic:
      datasource:
        master:
          username: root
          password: 123456
          url: jdbc:mysql://localhost:3306/yz-cloud?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=true&serverTimezone=GMT%2B8
          driver-class-name: com.mysql.cj.jdbc.Driver
        order: #没错就是我
          username: root
          password: 123456
          url: jdbc:mysql://localhost:3306/yz-order?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=true&serverTimezone=GMT%2B8
          driver-class-name: com.mysql.cj.jdbc.Driver

SysOrderController.java 测试

/**
 * 订单 Controller
 * 
 * @author yz
 */
@RestController
@RequestMapping("/api/order")
public class SysOrderController extends BaseController
{
    @Autowired
    private ISysOrderService sysOrderService;

    @GetMapping("/add/{userId}")
    public int add(@PathVariable("userId") Long userId)
    {
        SysOrder sysOrder = new SysOrder();
        sysOrder.setUserId(userId);
        sysOrder.setStatus("0");
        sysOrder.setOrderNo("123456789");
        return sysOrderService.insertSysOrder(sysOrder);
    }

    @GetMapping("/list")
    public List<SysOrder> list(SysOrder sysOrder)
    {
        return sysOrderService.selectSysOrderList(sysOrder);
    }

    @GetMapping("/query/{orderId}")
    public SysOrder query(@PathVariable("orderId") Long orderId)
    {
        return sysOrderService.selectSysOrderById(orderId);
    }
}

5、新增动态数据源配置DataSourceConfiguration.java

/**
 * 动态数据源配置
 *
 * @author yz
 */
@Configuration
public class DataSourceConfiguration
{
    /**
     * 分表数据源名称
     */
    private static final String SHARDING_DATA_SOURCE_NAME = "sharding";

    /**
     * 动态数据源配置项
     */
    @Autowired
    private DynamicDataSourceProperties properties;

    /**
     * shardingjdbc有四种数据源,需要根据业务注入不同的数据源
     *
     * <p>1. 未使用分片, 脱敏的名称(默认): shardingDataSource;
     * <p>2. 主从数据源: masterSlaveDataSource;
     * <p>3. 脱敏数据源:encryptDataSource;
     * <p>4. 影子数据源:shadowDataSource
     *
     */
    @Resource
    private DataSource shardingSphereDataSource;

    @Bean
    public DynamicDataSourceProvider dynamicDataSourceProvider()
    {
        Map<String, DataSourceProperty> datasourceMap = properties.getDatasource();
        return new AbstractDataSourceProvider()
        {
            @Override
            public Map<String, DataSource> loadDataSources()
            {
                Map<String, DataSource> dataSourceMap = createDataSourceMap(datasourceMap);
                // 将 shardingjdbc 管理的数据源也交给动态数据源管理
                dataSourceMap.put(SHARDING_DATA_SOURCE_NAME, shardingSphereDataSource);
                return dataSourceMap;
            }
        };
    }

    /**
     * 将动态数据源设置为首选的
     * 当spring存在多个数据源时, 自动注入的是首选的对象
     * 设置为主要的数据源之后,就可以支持shardingjdbc原生的配置方式了
     */
    @Primary
    @Bean
    public DataSource dataSource()
    {
        DynamicRoutingDataSource dataSource = new DynamicRoutingDataSource();
        dataSource.setPrimary(properties.getPrimary());
        dataSource.setStrict(properties.getStrict());
        dataSource.setStrategy(properties.getStrategy());
        dataSource.setP6spy(properties.getP6spy());
        dataSource.setSeata(properties.getSeata());
        return dataSource;
    }
  1. 新增yz-log数据库和oper_log_xxx四张表
DROP DATABASE IF EXISTS `yz-log`;

CREATE DATABASE  `yz-log` DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci;

SET NAMES utf8mb4;
SET FOREIGN_KEY_CHECKS = 0;

USE `yz-log`;

DROP TABLE IF EXISTS oper_log_get;
CREATE TABLE oper_log_get (
  oper_id           BIGINT(20)      NOT NULL AUTO_INCREMENT    COMMENT '日志主键',
  title             VARCHAR(50)     DEFAULT ''                 COMMENT '模块标题',
  business_type     INT(2)          DEFAULT 0                  COMMENT '业务类型(0其它 1新增 2修改 3删除)',
  method            VARCHAR(100)    DEFAULT ''                 COMMENT '方法名称',
  request_method    VARCHAR(10)     DEFAULT ''                 COMMENT '请求方式',
  operator_type     INT(1)          DEFAULT 0                  COMMENT '操作类别(0其它 1后台用户 2手机端用户)',
  oper_name         VARCHAR(50)     DEFAULT ''                 COMMENT '操作人员',
  dept_name         VARCHAR(50)     DEFAULT ''                 COMMENT '部门名称',
  oper_url          VARCHAR(255)    DEFAULT ''                 COMMENT '请求URL',
  oper_ip           VARCHAR(128)    DEFAULT ''                 COMMENT '主机地址',
  oper_location     VARCHAR(255)    DEFAULT ''                 COMMENT '操作地点',
  oper_param        VARCHAR(2000)   DEFAULT ''                 COMMENT '请求参数',
  json_result       VARCHAR(2000)   DEFAULT ''                 COMMENT '返回参数',
  STATUS            INT(1)          DEFAULT 0                  COMMENT '操作状态(0正常 1异常)',
  error_msg         VARCHAR(2000)   DEFAULT ''                 COMMENT '错误消息',
  oper_time         DATETIME                                   COMMENT '操作时间',
  PRIMARY KEY (oper_id)
) ENGINE=INNODB AUTO_INCREMENT=100 COMMENT = 'get操作日志记录';

DROP TABLE IF EXISTS oper_log_post;
CREATE TABLE oper_log_post (
  oper_id           BIGINT(20)      NOT NULL AUTO_INCREMENT    COMMENT '日志主键',
  title             VARCHAR(50)     DEFAULT ''                 COMMENT '模块标题',
  business_type     INT(2)          DEFAULT 0                  COMMENT '业务类型(0其它 1新增 2修改 3删除)',
  method            VARCHAR(100)    DEFAULT ''                 COMMENT '方法名称',
  request_method    VARCHAR(10)     DEFAULT ''                 COMMENT '请求方式',
  operator_type     INT(1)          DEFAULT 0                  COMMENT '操作类别(0其它 1后台用户 2手机端用户)',
  oper_name         VARCHAR(50)     DEFAULT ''                 COMMENT '操作人员',
  dept_name         VARCHAR(50)     DEFAULT ''                 COMMENT '部门名称',
  oper_url          VARCHAR(255)    DEFAULT ''                 COMMENT '请求URL',
  oper_ip           VARCHAR(128)    DEFAULT ''                 COMMENT '主机地址',
  oper_location     VARCHAR(255)    DEFAULT ''                 COMMENT '操作地点',
  oper_param        VARCHAR(2000)   DEFAULT ''                 COMMENT '请求参数',
  json_result       VARCHAR(2000)   DEFAULT ''                 COMMENT '返回参数',
  STATUS            INT(1)          DEFAULT 0                  COMMENT '操作状态(0正常 1异常)',
  error_msg         VARCHAR(2000)   DEFAULT ''                 COMMENT '错误消息',
  oper_time         DATETIME                                   COMMENT '操作时间',
  PRIMARY KEY (oper_id)
) ENGINE=INNODB AUTO_INCREMENT=100 COMMENT = 'post操作日志记录';

DROP TABLE IF EXISTS oper_log_put;
CREATE TABLE oper_log_put (
  oper_id           BIGINT(20)      NOT NULL AUTO_INCREMENT    COMMENT '日志主键',
  title             VARCHAR(50)     DEFAULT ''                 COMMENT '模块标题',
  business_type     INT(2)          DEFAULT 0                  COMMENT '业务类型(0其它 1新增 2修改 3删除)',
  method            VARCHAR(100)    DEFAULT ''                 COMMENT '方法名称',
  request_method    VARCHAR(10)     DEFAULT ''                 COMMENT '请求方式',
  operator_type     INT(1)          DEFAULT 0                  COMMENT '操作类别(0其它 1后台用户 2手机端用户)',
  oper_name         VARCHAR(50)     DEFAULT ''                 COMMENT '操作人员',
  dept_name         VARCHAR(50)     DEFAULT ''                 COMMENT '部门名称',
  oper_url          VARCHAR(255)    DEFAULT ''                 COMMENT '请求URL',
  oper_ip           VARCHAR(128)    DEFAULT ''                 COMMENT '主机地址',
  oper_location     VARCHAR(255)    DEFAULT ''                 COMMENT '操作地点',
  oper_param        VARCHAR(2000)   DEFAULT ''                 COMMENT '请求参数',
  json_result       VARCHAR(2000)   DEFAULT ''                 COMMENT '返回参数',
  STATUS            INT(1)          DEFAULT 0                  COMMENT '操作状态(0正常 1异常)',
  error_msg         VARCHAR(2000)   DEFAULT ''                 COMMENT '错误消息',
  oper_time         DATETIME                                   COMMENT '操作时间',
  PRIMARY KEY (oper_id)
) ENGINE=INNODB AUTO_INCREMENT=100 COMMENT = 'put操作日志记录';

DROP TABLE IF EXISTS oper_log_delete;
CREATE TABLE oper_log_delete (
  oper_id           BIGINT(20)      NOT NULL AUTO_INCREMENT    COMMENT '日志主键',
  title             VARCHAR(50)     DEFAULT ''                 COMMENT '模块标题',
  business_type     INT(2)          DEFAULT 0                  COMMENT '业务类型(0其它 1新增 2修改 3删除)',
  method            VARCHAR(100)    DEFAULT ''                 COMMENT '方法名称',
  request_method    VARCHAR(10)     DEFAULT ''                 COMMENT '请求方式',
  operator_type     INT(1)          DEFAULT 0                  COMMENT '操作类别(0其它 1后台用户 2手机端用户)',
  oper_name         VARCHAR(50)     DEFAULT ''                 COMMENT '操作人员',
  dept_name         VARCHAR(50)     DEFAULT ''                 COMMENT '部门名称',
  oper_url          VARCHAR(255)    DEFAULT ''                 COMMENT '请求URL',
  oper_ip           VARCHAR(128)    DEFAULT ''                 COMMENT '主机地址',
  oper_location     VARCHAR(255)    DEFAULT ''                 COMMENT '操作地点',
  oper_param        VARCHAR(2000)   DEFAULT ''                 COMMENT '请求参数',
  json_result       VARCHAR(2000)   DEFAULT ''                 COMMENT '返回参数',
  STATUS            INT(1)          DEFAULT 0                  COMMENT '操作状态(0正常 1异常)',
  error_msg         VARCHAR(2000)   DEFAULT ''                 COMMENT '错误消息',
  oper_time         DATETIME                                   COMMENT '操作时间',
  PRIMARY KEY (oper_id)
) ENGINE=INNODB AUTO_INCREMENT=100 COMMENT = 'delete操作日志记录';

7、省略service和mapper

修改OperLogServiceImpl.java,切换分库分表

/**
 * 操作日志 服务层处理
 * 
 * @author yz
 */
@Service
public class OperLogServiceImpl implements IOperLogService
{
    @Autowired
    private OperLogMapper operLogMapper;

    /**
     * 新增操作日志
     * 
     * @param operLog 操作日志对象
     * @return 结果
     */
    @Override
    @DS("sharding")
    public int insertOperlog(OperLog operLog)
    {
        return operLogMapper.insertOperlog(operLog);
    }

    /**
     * 查询系统操作日志集合
     * 
     * @param operLog 操作日志对象
     * @return 操作日志集合
     */
    @Override
    @DS("sharding")
    public List<OperLog> selectOperLogList(OperLog operLog)
    {
        return operLogMapper.selectOperLogList(operLog);
    }

    /**
     * 批量删除系统操作日志
     * 
     * @param operIds 需要删除的操作日志ID
     * @return 结果
     */
    @Override
    @DS("sharding")
    public int deleteOperLogByIds(Long[] operIds)
    {
        return operLogMapper.deleteOperLogByIds(operIds);
    }

    /**
     * 查询操作日志详细
     * 
     * @param operId 操作ID
     * @return 操作日志对象
     */
    @Override
    @DS("sharding")
    public OperLog selectOperLogById(Long operId)
    {
        return operLogMapper.selectOperLogById(operId);
    }

    /**
     * 清空操作日志
     */
    @Override
    @DS("sharding")
    public void cleanOperLog()
    {
        operLogMapper.cleanOperLog();
    }
}

@DS("sharding")其中sharding就是定义的分库分表 为了不迷糊且看以下

 # 分库分表配置
  shardingsphere:
    datasource:
      ds0:
        driver-class-name: com.mysql.cj.jdbc.Driver
        type: com.zaxxer.hikari.HikariDataSource
        username: root
        password: 123456
        jdbc-url: jdbc:mysql://localhost:3306/yz-log?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=true&serverTimezone=GMT%2B8
      names: ds0
    props:
      sql-show: true
    rules:
      sharding:#没错就是我
        sharding-algorithms:
          table-inline:
            props:                    #以下根据http请求进入不同表 如GET 
              algorithm-expression: sys_oper_log_$->{request_method}
            type: INLINE
        tables:
          oper_log:                #以下根据http请求进入不同表 如GET 
            actual-data-nodes: ds0.sys_oper_log_GET,ds0.sys_oper_log_POST,ds0.sys_oper_log_PUT,ds0.sys_oper_log_DELETE
            table-strategy:
              standard:
                sharding-algorithm-name: table-inline
                sharding-column: request_method

8、新增分库分表测试类TestOperlogController.java

@RestController
@RequestMapping("/api/operlog")
public class TestOperlogController extends BaseController
{
    @Autowired
    private IOperLogService operLogService;

    @GetMapping("/{method}")
    public int operlog(@PathVariable("method") String method)
    {
        OperLog operLog = new OperLog();
        operLog.setTitle("测试数据");
        operLog.setOperName("admin");
        operLog.setRequestMethod(method);
        return operLogService.insertOperlog(operLog);
    }

    @GetMapping("/list")
    public List<OperLog> list()
    {
        return operLogService.selectOperLogList(new OperLog());
    }
}

9、启动DemoApplication.java进行测试验证

订单数据库测试

访问 http://localhost:8080/api/order/add/1 入到yz-order库sys_order表

查询 http://localhost:8080/api/order/list

查询 http://localhost:8080/api/order/query/1

分库分表测试

访问 http://localhost:8080/api/operlog/GET 入到yz-log库oper_log_get表

访问 http://localhost:8080/api/operlog/POST 入到yz-log库oper_log_post表

访问 http://localhost:8080/api/operlog/PUT 入到yz-log库oper_log_put表

访问 http://localhost:8080/api/operlog/DELETE 入到yz-log库oper_log_delete表

查询 http://localhost:8080/api/operlog/list


本文转载自: https://blog.csdn.net/qq_37544675/article/details/129472328
版权归原作者 扭曲的影子 所有, 如有侵权,请联系我们删除。

“shardingsphere分库分表集成多数据源”的评论:

还没有评论