spring boot使用sharding jdbc的配置方式

作者:J猿 时间:2022-02-16 00:29:15 

本文介绍了spring boot使用sharding jdbc的配置方式,分享给大家,具体如下:

说明

要排除DataSourceAutoConfiguration,否则多数据源无法配置


@SpringBootApplication
@EnableAutoConfiguration(exclude={DataSourceAutoConfiguration.class})
public class Application {

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

}

配置的多个数据源交给sharding-jdbc管理,sharding-jdbc创建一个DataSource数据源提供给mybatis使用

官方文档:http://shardingjdbc.io/index_zh.html

步骤

配置多个数据源,数据源的名称最好要有一定的规则,方便配置分库的计算规则


@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操作

强制路由

  1. 使用ThreadLocal机制实现,在执行数据库操作之前通过HintManager改变用于计算路由的值

  2. 设置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());

事务

  1. sharding-jdbc-transaction实现柔性事务(默认提供了基于内存的事务日志存储器和内嵌异步作业),可结合elastic-job(sharding-jdbc-transaction-async-job)实现异步柔性事务

  2. 没有与spring结合使用的方式,需要自己封装

来源:https://my.oschina.net/dengfuwei/blog/1595151

标签:spring,boot,sharding,jdbc
0
投稿

猜你喜欢

  • mybatis-plus用insertBatchSomeColumn方法批量新增指定字段

    2022-03-02 10:20:58
  • javaweb图书商城设计之用户模块(1)

    2023-10-30 09:22:57
  • Spring JPA之find拓展方法示例详解

    2021-12-11 03:50:49
  • C#实现工厂方法模式

    2023-12-10 05:17:37
  • C#中四步轻松使用log4net记录本地日志的方法

    2021-12-22 02:23:16
  • Mybatis 逆向工程的三种方法详解

    2023-08-10 22:27:20
  • 详解APP微信支付(java后台_统一下单和回调)

    2023-11-10 17:26:42
  • Android 动态加载二维码视图生成快照的示例

    2023-08-04 19:57:54
  • mybatis group by substr函数传参报错的解决

    2022-09-10 03:44:34
  • Java stream sorted使用 Comparator 进行多字段排序的方法

    2022-07-26 05:02:13
  • Spring Boot中使用JDBC Templet的方法教程

    2021-09-06 06:04:38
  • 详解Android自定义View--自定义柱状图

    2023-10-13 19:33:06
  • C#自适应合并文件的方法

    2023-09-28 05:27:13
  • Java命令设计模式详解

    2022-07-14 04:38:31
  • Android实现小米相机底部滑动指示器

    2023-03-12 04:57:00
  • WinForm实现读取Resource中文件的方法

    2021-05-25 18:29:45
  • C#接口INotifyPropertyChanged使用方法

    2021-11-22 13:33:53
  • Mybatis的mapper.xml中if标签test判断的用法说明

    2023-12-23 23:04:16
  • Java利用apache ftp工具实现文件上传下载和删除功能

    2022-03-17 02:04:01
  • Java基于Tcp协议的socket编程实例

    2022-03-08 00:04:13
  • asp之家 软件编程 m.aspxhome.com