spring boot使用sharding jdbc的配置

简介: spring boot使用sharding jdbc的配置方式

说明

  • 要排除DataSourceAutoConfiguration,否则多数据源无法配置
@SpringBootApplication
@EnableAutoConfiguration(exclude={DataSourceAutoConfiguration.class})
public class Application {

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

步骤

  • 配置多个数据源,数据源的名称最好要有一定的规则,方便配置分库的计算规则
@Bean(initMethod="init", destroyMethod="close", name="dataSource0")
@ConfigurationProperties(prefix = "spring.datasource")
public DataSource dataSource0(){
    return new DruidDataSource();
}

@Bean(initMethod="init", destroyMethod="close", name="dataSource1")
@ConfigurationProperties(prefix = "spring.datasource2")
public DataSource dataSource1(){
    return new DruidDataSource();
}
  • 配置数据源规则,即将多个数据源交给sharding-jdbc管理,并且可以设置默认的数据源,当表没有配置分库规则时会使用默认的数据源
@Bean
public DataSourceRule dataSourceRule(@Qualifier("dataSource0") DataSource dataSource0, 
        @Qualifier("dataSource1") DataSource dataSource1){
    Map<String, DataSource> dataSourceMap = new HashMap<>();
    dataSourceMap.put("dataSource0", dataSource0);
    dataSourceMap.put("dataSource1", dataSource1);
    return new DataSourceRule(dataSourceMap, "dataSource0");
}
  • 配置数据源策略和表策略,具体策略需要自己实现
@Bean
public ShardingRule shardingRule(DataSourceRule dataSourceRule){
    //表策略
    TableRule orderTableRule = TableRule.builder("t_order")
            .actualTables(Arrays.asList("t_order_0", "t_order_1"))
            .tableShardingStrategy(new TableShardingStrategy("order_id", new ModuloTableShardingAlgorithm()))
            .dataSourceRule(dataSourceRule)
            .build();
    TableRule orderItemTableRule = TableRule.builder("t_order_item")
            .actualTables(Arrays.asList("t_order_item_0", "t_order_item_1"))
            .tableShardingStrategy(new TableShardingStrategy("order_id", new ModuloTableShardingAlgorithm()))
            .dataSourceRule(dataSourceRule)
            .build();
    //绑定表策略,在查询时会使用主表策略计算路由的数据源,因此需要约定绑定表策略的表的规则需要一致,可以一定程度提高效率
    List<BindingTableRule> bindingTableRules = new ArrayList<BindingTableRule>();
    bindingTableRules.add(new BindingTableRule(Arrays.asList(orderTableRule, orderItemTableRule)));
    return ShardingRule.builder()
            .dataSourceRule(dataSourceRule)
            .tableRules(Arrays.asList(orderTableRule, orderItemTableRule))
            .bindingTableRules(bindingTableRules)
            .databaseShardingStrategy(new DatabaseShardingStrategy("user_id", new ModuloDatabaseShardingAlgorithm()))
            .tableShardingStrategy(new TableShardingStrategy("order_id", new ModuloTableShardingAlgorithm()))
            .build();
}
  • 创建sharding-jdbc的数据源DataSource,MybatisAutoConfiguration会使用此数据源
@Bean("dataSource")
public DataSource shardingDataSource(ShardingRule shardingRule){
    return ShardingDataSourceFactory.createDataSource(shardingRule);
}
  • 需要手动配置事务管理器(原因未知)
//需要手动声明配置事务
@Bean
public DataSourceTransactionManager transactitonManager(@Qualifier("dataSource") DataSource dataSource){
    return new DataSourceTransactionManager(dataSource);
}
  • 分库策略的简单实现,接口:DatabaseShardingAlgorithm
import java.util.Collection;
import java.util.LinkedHashSet;

import com.dangdang.ddframe.rdb.sharding.api.ShardingValue;
import com.dangdang.ddframe.rdb.sharding.api.strategy.database.SingleKeyDatabaseShardingAlgorithm;
import com.google.common.collect.Range;

/**
 * Created by fuwei.deng on 2017年5月11日.
 */
public class ModuloDatabaseShardingAlgorithm implements SingleKeyDatabaseShardingAlgorithm<Long> {

    @Override
    public String doEqualSharding(Collection<String> databaseNames, ShardingValue<Long> shardingValue) {
        for (String each : databaseNames) {
            if (each.endsWith(shardingValue.getValue() % 2 + "")) {
                return each;
            }
        }
        throw new IllegalArgumentException();
    }
    
    @Override
    public Collection<String> doInSharding(Collection<String> databaseNames, ShardingValue<Long> shardingValue) {
        Collection<String> result = new LinkedHashSet<>(databaseNames.size());
        for (Long value : shardingValue.getValues()) {
            for (String tableName : databaseNames) {
                if (tableName.endsWith(value % 2 + "")) {
                    result.add(tableName);
                }
            }
        }
        return result;
    }
    
    @Override
    public Collection<String> doBetweenSharding(Collection<String> databaseNames, ShardingValue<Long> shardingValue) {
        Collection<String> result = new LinkedHashSet<>(databaseNames.size());
        Range<Long> range = (Range<Long>) shardingValue.getValueRange();
        for (Long i = range.lowerEndpoint(); i <= range.upperEndpoint(); i++) {
            for (String each : databaseNames) {
                if (each.endsWith(i % 2 + "")) {
                    result.add(each);
                }
            }
        }
        return result;
    }

}
  • 分表策略的基本实现,接口:TableShardingAlgorithm
import java.util.Collection;
import java.util.LinkedHashSet;

import com.dangdang.ddframe.rdb.sharding.api.ShardingValue;
import com.dangdang.ddframe.rdb.sharding.api.strategy.table.SingleKeyTableShardingAlgorithm;
import com.google.common.collect.Range;

/**
 * Created by fuwei.deng on 2017年5月11日.
 */
public class ModuloTableShardingAlgorithm implements SingleKeyTableShardingAlgorithm<Long> {

    @Override
    public String doEqualSharding(Collection<String> tableNames, ShardingValue<Long> shardingValue) {
        for (String each : tableNames) {
            if (each.endsWith(shardingValue.getValue() % 2 + "")) {
                return each;
            }
        }
        throw new IllegalArgumentException();
    }
    
    @Override
    public Collection<String> doInSharding(Collection<String> tableNames, ShardingValue<Long> shardingValue) {
        Collection<String> result = new LinkedHashSet<>(tableNames.size());
        for (Long value : shardingValue.getValues()) {
            for (String tableName : tableNames) {
                if (tableName.endsWith(value % 2 + "")) {
                    result.add(tableName);
                }
            }
        }
        return result;
    }
    
    @Override
    public Collection<String> doBetweenSharding(Collection<String> tableNames, ShardingValue<Long> shardingValue) {
        Collection<String> result = new LinkedHashSet<>(tableNames.size());
        Range<Long> range = (Range<Long>) shardingValue.getValueRange();
        for (Long i = range.lowerEndpoint(); i <= range.upperEndpoint(); i++) {
            for (String each : tableNames) {
                if (each.endsWith(i % 2 + "")) {
                    result.add(each);
                }
            }
        }
        return result;
    }

}
  • 至此,分库分表的功能已经实现

读写分离

  • 读写分离需在创建DataSourceRule之前加一层主从数据源的创建
// 构建读写分离数据源, 读写分离数据源实现了DataSource接口, 可直接当做数据源处理. 
// masterDataSource0, slaveDataSource00, slaveDataSource01等为使用DBCP等连接池配置的真实数据源
DataSource masterSlaveDs0 = MasterSlaveDataSourceFactory.createDataSource("ms_0", 
                    masterDataSource0, slaveDataSource00, slaveDataSource01);
DataSource masterSlaveDs1 = MasterSlaveDataSourceFactory.createDataSource("ms_1", 
                    masterDataSource1, slaveDataSource11, slaveDataSource11);

// 构建分库分表数据源
Map<String, DataSource> dataSourceMap = new HashMap<>(2);
dataSourceMap.put("ms_0", masterSlaveDs0);
dataSourceMap.put("ms_1", masterSlaveDs1);

// 通过ShardingDataSourceFactory继续创建ShardingDataSource
  • 强制使用主库时
HintManager hintManager = HintManager.getInstance();
hintManager.setMasterRouteOnly();
// 继续JDBC操作

强制路由

  • 使用ThreadLocal机制实现,在执行数据库操作之前通过HintManager改变用于计算路由的值
  • 设置HintManager的时候分库和分表的策略必须同时设置,并且设置后需要路由的表都需要设置用于计算路由的值。比如强制路由后需要操作t_order和t_order_item两个表,那么两个表的分库和分表的策略都需要设置
HintManager hintManager = HintManager.getInstance();
hintManager.addDatabaseShardingValue("t_order", "user_id", 1L);
hintManager.addTableShardingValue("t_order", "order_id", order.getOrderId());
hintManager.addDatabaseShardingValue("t_order_item", "user_id", 1L);
hintManager.addTableShardingValue("t_order_item", "order_id", order.getOrderId());

事务

  • sharding-jdbc-transaction实现柔性事务(默认提供了基于内存的事务日志存储器和内嵌异步作业),可结合elastic-job(sharding-jdbc-transaction-async-job)实现异步柔性事务
  • 没有与spring结合使用的方式,需要自己封装
目录
相关文章
|
8天前
|
Java 开发者 微服务
手写模拟Spring Boot自动配置功能
【11月更文挑战第19天】随着微服务架构的兴起,Spring Boot作为一种快速开发框架,因其简化了Spring应用的初始搭建和开发过程,受到了广大开发者的青睐。自动配置作为Spring Boot的核心特性之一,大大减少了手动配置的工作量,提高了开发效率。
28 0
|
1月前
|
Java API 数据库
构建RESTful API已经成为现代Web开发的标准做法之一。Spring Boot框架因其简洁的配置、快速的启动特性及丰富的功能集而备受开发者青睐。
【10月更文挑战第11天】本文介绍如何使用Spring Boot构建在线图书管理系统的RESTful API。通过创建Spring Boot项目,定义`Book`实体类、`BookRepository`接口和`BookService`服务类,最后实现`BookController`控制器来处理HTTP请求,展示了从基础环境搭建到API测试的完整过程。
42 4
|
1月前
|
Java API 数据库
Spring Boot框架因其简洁的配置、快速的启动特性及丰富的功能集而备受开发者青睐
本文通过在线图书管理系统案例,详细介绍如何使用Spring Boot构建RESTful API。从项目基础环境搭建、实体类与数据访问层定义,到业务逻辑实现和控制器编写,逐步展示了Spring Boot的简洁配置和强大功能。最后,通过Postman测试API,并介绍了如何添加安全性和异常处理,确保API的稳定性和安全性。
37 0
|
25天前
|
Java API Spring
在 Spring 配置文件中配置 Filter 的步骤
【10月更文挑战第21天】在 Spring 配置文件中配置 Filter 是实现请求过滤的重要手段。通过合理的配置,可以灵活地对请求进行处理,满足各种应用需求。还可以根据具体的项目要求和实际情况,进一步深入研究和优化 Filter 的配置,以提高应用的性能和安全性。
|
12天前
|
缓存 IDE Java
SpringBoot入门(7)- 配置热部署devtools工具
SpringBoot入门(7)- 配置热部署devtools工具
25 2
 SpringBoot入门(7)- 配置热部署devtools工具
|
11天前
|
Java 数据库连接
SpringBoot配置多数据源实战
第四届光学与机器视觉国际学术会议(ICOMV 2025) 2025 4th International Conference on Optics and Machine Vision
39 8
|
8天前
|
Java 数据库连接 数据库
springboot启动配置文件-bootstrap.yml常用基本配置
以上是一些常用的基本配置项,在实际应用中可能会根据需求有所变化。通过合理配置 `bootstrap.yml`文件,可以确保应用程序在启动阶段加载正确的配置,并顺利启动运行。
16 2
|
8天前
|
存储 运维 安全
Spring运维之boot项目多环境(yaml 多文件 proerties)及分组管理与开发控制
通过以上措施,可以保证Spring Boot项目的配置管理在专业水准上,并且易于维护和管理,符合搜索引擎收录标准。
20 2
|
17天前
|
Java Spring
[Spring]aop的配置与使用
本文介绍了AOP(面向切面编程)的基本概念和核心思想。AOP是Spring框架的核心功能之一,通过动态代理在不修改原代码的情况下注入新功能。文章详细解释了连接点、切入点、通知、切面等关键概念,并列举了前置通知、后置通知、最终通知、异常通知和环绕通知五种通知类型。
28 1
|
1月前
|
SQL JSON Java
mybatis使用三:springboot整合mybatis,使用PageHelper 进行分页操作,并整合swagger2。使用正规的开发模式:定义统一的数据返回格式和请求模块
这篇文章介绍了如何在Spring Boot项目中整合MyBatis和PageHelper进行分页操作,并且集成Swagger2来生成API文档,同时定义了统一的数据返回格式和请求模块。
54 1
mybatis使用三:springboot整合mybatis,使用PageHelper 进行分页操作,并整合swagger2。使用正规的开发模式:定义统一的数据返回格式和请求模块