presto mysql 分表_【Spring Boot】Spring Boot之整合Sharding-JDBC(java config方式)实现分库分表(水平拆分)...

一、概念先行

1)SQL相关的

逻辑表:水平拆分的数据库(表)的相同逻辑和数据结构表的总称。例:订单数据根据主键尾数拆分为2张表,分别是t_order_0到t_order_1,他们的逻辑表名为t_order。

真实表:在分片的数据库中真实存在的物理表。例:示例中的t_order_0到t_order_1

数据节点:数据分片的最小单元。由数据源名称和数据表组成,例:ds_0.t_order_0;ds_0.t_order_1;

绑定表:指分片规则一致的主表和子表。例如:t_order表和t_order_item表,均按照order_id分片,则此两张表互为绑定表关系。绑定表之间的多表关联查询不会出现笛卡尔积关联,关联查询效率将大大提升。

广播表:指所有的分片数据源中都存在的表,表结构和表中的数据在每个数据库中均完全一致。适用于数据量不大且需要与海量数据的表进行关联查询的场景,例如:字典表,示例中的t

2)分片相关

分片键:用于分片的数据库字段,是将数据库(表)水平拆分的关键字段。例:将订单表中的订单主键的尾数取模分片,则订单主键为分片字段。 SQL中如果无分片字段,将执行全路由,性能较差。 除了对单分片字段的支持,ShardingSphere也支持根据多个字段进行分片。

分片算法:通过分片算法将数据分片,支持通过=、>=、<=、>、

目前提供4种分片算法:

精确分片算法:对应PreciseShardingAlgorithm,用于处理使用单一键作为分片键的=与IN进行分片的场景。需要配合StandardShardingStrategy使用。

范围分片算法:对应RangeShardingAlgorithm,用于处理使用单一键作为分片键的BETWEEN AND、>、=、<=进行分片的场景。需要配合StandardShardingStrategy使用。

复合分片算法:对应ComplexKeysShardingAlgorithm,用于处理使用多键作为分片键进行分片的场景,包含多个分片键的逻辑较复杂,需要应用开发者自行处理其中的复杂度。需要配合ComplexShardingStrategy使用。

Hint分片算法:对应HintShardingAlgorithm,用于处理使用Hint行分片的场景。需要配合HintShardingStrategy使用。

分片策略:包含分片键和分片算法,由于分片算法的独立性,将其独立抽离。真正可用于分片操作的是分片键 + 分片算法,也就是分片策略。

目前提供5种分片策略。

标准分片策略:对应StandardShardingStrategy。提供对SQL语句中的=, >, =, <=, IN和BETWEEN AND的分片操作支持。StandardShardingStrategy只支持单分片键,提供PreciseShardingAlgorithm和RangeShardingAlgorithm两个分片算法。PreciseShardingAlgorithm是必选的,用于处理=和IN的分片。RangeShardingAlgorithm是可选的,用于处理BETWEEN AND, >, =, <=分片,如果不配置RangeShardingAlgorithm,SQL中的BETWEEN AND将按照全库路由处理。

复合分片策略:对应ComplexShardingStrategy。复合分片策略。提供对SQL语句中的=, >, =, <=, IN和BETWEEN AND的分片操作支持。ComplexShardingStrategy支持多分片键,由于多分片键之间的关系复杂,因此并未进行过多的封装,而是直接将分片键值组合以及分片操作符透传至分片算法,完全由应用开发者实现,提供最大的灵活度。

行表达式分片策略:对应InlineShardingStrategy。使用Groovy的表达式,提供对SQL语句中的=和IN的分片操作支持,只支持单分片键。对于简单的分片算法,可以通过简单的配置使用,从而避免繁琐的Java代码开发,如: t_user_$->{u_id % 8} 表示t_user表根据u_id模8,而分成8张表,表名称为t_user_0到t_user_7。

Hint分片策略:对应HintShardingStrategy。通过Hint指定分片值而非从SQL中提取分片值的方式进行分片的策略。

不分片策略:对应NoneShardingStrategy。不分片的策略。

3)配置相关

分片规则:分片规则配置的总入口。包含数据源配置、表配置、绑定表配置以及读写分离配置等。

数据源配置:真实数据源列表。

表配置:逻辑表名称、数据节点与分表规则的配置

数据节点配置:用于配置逻辑表与真实表的映射关系。

分片策略配置:

数据源分片策略:对应于DatabaseShardingStrategy。用于配置数据被分配的目标数据源。

表分片策略:对应于TableShardingStrategy。用于配置数据被分配的目标表,该目标表存在与该数据的目标数据源内。故表分片策略是依赖与数据源分片策略的结果的。

自增主键生成策略:通过在客户端生成自增主键替换以数据库原生自增主键的方式,做到分布式主键无重复。(雪花算法)

二、整合步骤

1)引入相关Maven坐标

org.mybatis.spring.boot

mybatis-spring-boot-starter

2.1.2

org.apache.shardingsphere

sharding-jdbc-core

4.0.1

mysql

mysql-connector-java

8.0.19

2)定义相关配置类(DataSourceConfig ===> MybatisConfig ==> TransactionConfig)

ShardingSphereDataSourceConfig

importjavax.sql.DataSource;importjava.lang.management.ManagementFactory;importjava.sql.SQLException;import java.util.*;/*** @Author zhangboqing

* @Date 2020/4/25*/@Configuration

@Slf4jpublic classShardingSphereDataSourceConfig {

@Bean("shardingDataSource")

DataSource getShardingDataSource()throwsSQLException {

ShardingRuleConfiguration shardingRuleConfig= newShardingRuleConfiguration();

shardingRuleConfig.setDefaultDataSourceName("ds0");

shardingRuleConfig.getTableRuleConfigs().add(getOrderTableRuleConfiguration());

shardingRuleConfig.getTableRuleConfigs().add(getOrderItemTableRuleConfiguration());

shardingRuleConfig.getBindingTableGroups().add("t_order, t_order_item");

shardingRuleConfig.getBroadcastTables().add("t_config");

shardingRuleConfig.setDefaultDatabaseShardingStrategyConfig(new InlineShardingStrategyConfiguration("user_id", "ds${user_id % 2}"));

shardingRuleConfig.setDefaultTableShardingStrategyConfig(getShardingStrategyConfiguration());//ShardingPropertiesConstant相关配置选项

Properties properties = newProperties();

properties.put("sql.show",true);returnShardingDataSourceFactory.createDataSource(createDataSourceMap(), shardingRuleConfig, properties);

}privateShardingStrategyConfiguration getShardingStrategyConfiguration(){//精确匹配

PreciseShardingAlgorithm preciseShardingAlgorithm = new PreciseShardingAlgorithm() {

@Overridepublic String doSharding(Collection availableTargetNames, PreciseShardingValueshardingValue) {

String prefix=shardingValue.getLogicTableName();

Long orderId=shardingValue.getValue();long index = orderId % 2;//t_order + "" + 0 = t_order0

String tableName = prefix + "" +index;//精确查询、更新之类的,可以返回不存在表,进而给前端抛出异常和警告。

if (availableTargetNames.contains(tableName) == false) {

LogUtils.error(log,"PreciseSharding","orderId:{},不存在对应的数据库表{}!", orderId, tableName);returnavailableTargetNames.iterator().next();

}returntableName;//return availableTargetNames.iterator().next();

}

};//范围匹配

RangeShardingAlgorithm rangeShardingAlgorithm = new RangeShardingAlgorithm() {

@Overridepublic Collection doSharding(Collection availableTargetNames, RangeShardingValueshardingValue) {

String prefix=shardingValue.getLogicTableName();

Collection resList = new ArrayList<>();

Range valueRange =shardingValue.getValueRange();if (!valueRange.hasLowerBound() || !valueRange.hasUpperBound()) {returnavailableTargetNames;

}long lower =shardingValue.getValueRange().lowerEndpoint();

BoundType lowerBoundType=shardingValue.getValueRange().lowerBoundType();long upper =shardingValue.getValueRange().upperEndpoint();

BoundType upperBoundType=shardingValue.getValueRange().upperBoundType();long startValue =lower;long endValue =upper;if(lowerBoundType.equals(BoundType.OPEN)) {

startValue++;

}if(upperBoundType.equals(BoundType.OPEN)) {

endValue--;

}for (long i = startValue; i <= endValue; i++) {long index = i % 2;

String res= prefix + "" +index;//精确查询、更新之类的,可以返回不存在表,进而给前端抛出异常和警告。

if (availableTargetNames.contains(res) == false) {

LogUtils.error(log,"RangeSharding","orderId:{},不存在对应的数据库表{}!", i, res);

resList.add(res);

}

}if (resList.size() == 0) {

LogUtils.error(log,"RangeSharding","无法获取对应表,因此将对全表进行查询!orderId范围为:{}到{}",startValue,endValue);returnavailableTargetNames;

}returnresList;

}

};

ShardingStrategyConfiguration strategyConf= new StandardShardingStrategyConfiguration("order_id", preciseShardingAlgorithm, rangeShardingAlgorithm);returnstrategyConf;

}

TableRuleConfiguration getOrderTableRuleConfiguration() {//逻辑表 + 实际节点

TableRuleConfiguration result = new TableRuleConfiguration("t_order", "ds${0..1}.t_order${0..1}");//主键生成配置

result.setKeyGeneratorConfig(getKeyGeneratorConfigurationForTOrder());returnresult;

}

TableRuleConfiguration getOrderItemTableRuleConfiguration() {

TableRuleConfiguration result= new TableRuleConfiguration("t_order_item", "ds${0..1}.t_order_item${0..1}");

result.setKeyGeneratorConfig(getKeyGeneratorConfigurationForTOrderItem());returnresult;

}

MapcreateDataSourceMap() {

Map result = new HashMap<>();

result.put("ds0", DataSourceUtils.createDataSource("ds0"));

result.put("ds1", DataSourceUtils.createDataSource("ds1"));returnresult;

}privateKeyGeneratorConfiguration getKeyGeneratorConfigurationForTOrder() {

Properties keyGeneratorProp=getKeyGeneratorProperties();return new KeyGeneratorConfiguration("SNOWFLAKE", "order_id", keyGeneratorProp);

}privateProperties getKeyGeneratorProperties() {

Properties keyGeneratorProp= newProperties();

String distributeProcessIdentify= NetUtils.getLocalAddress() + ":" +getProcessId();

String workId=String.valueOf(convertString2Long(distributeProcessIdentify));

keyGeneratorProp.setProperty("worker.id", workId);

LogUtils.info(log,"shardingsphere init", "shardingsphere work id raw string is {}, work id is {}", distributeProcessIdentify, workId);returnkeyGeneratorProp;

}privateKeyGeneratorConfiguration getKeyGeneratorConfigurationForTOrderItem() {

Properties keyGeneratorProp=getKeyGeneratorProperties();return new KeyGeneratorConfiguration("SNOWFLAKE", "id", keyGeneratorProp);

}privateString getProcessId(){

String name=ManagementFactory.getRuntimeMXBean().getName();

String pid= name.split("@")[0];returnpid;

}privateLong convertString2Long(String str){long hashCode = str.hashCode() +System.currentTimeMillis();if(hashCode < 0){

hashCode= -hashCode;

}return hashCode % (1L << 10);

}

}

ShardingsphereMybatisConfig

/*** @Author zhangboqing

* @Date 2020/4/23*/@Configuration

@MapperScan(basePackages= "com.zbq.springbootshardingjdbcjavaconfigdemo.dao",sqlSessionFactoryRef = "sqlSessionFactoryForShardingjdbc")public classShardingsphereMybatisConfig {

@Autowired

@Qualifier("shardingDataSource")privateDataSource dataSource;

@Bean("sqlSessionFactoryForShardingjdbc")public SqlSessionFactory sqlSessionFactoryForShardingjdbc() throwsException {

SqlSessionFactoryBean sessionFactory= newSqlSessionFactoryBean();

sessionFactory.setDataSource(dataSource);//sessionFactory.setMapperLocations(new PathMatchingResourcePatternResolver().//getResources("classpath*:**/*.xml"));

sessionFactory.setTypeAliasesPackage("com.zbq.springbootshardingjdbcjavaconfigdemo.domain.entity");

org.apache.ibatis.session.Configuration configuration= neworg.apache.ibatis.session.Configuration();

configuration.setMapUnderscoreToCamelCase(true);

sessionFactory.setConfiguration(configuration);returnsessionFactory.getObject();

}

}

ShardingsphereTransactionConfig

/**

* @Author zhangboqing

* @Date 2020/4/25

*/

@Configuration

@EnableTransactionManagement

public class ShardingsphereTransactionConfig {

@Bean

@Autowired

public PlatformTransactionManager shardingsphereTransactionManager(@Qualifier("shardingDataSource") DataSource dataSource) {

return new DataSourceTransactionManager(dataSource);

}

}

3)测试

1.定义dao

@Mapperpublic interfaceTOrderDao {

@Insert("insert into t_order values(#{orderId},#{orderNo},#{userId})")public int insert(@Param("orderId") Long orderId, @Param("orderNo") String orderNo,@Param("userId") Long userId);

@Insert("insert into t_order(order_no,user_id) values(#{orderNo},#{userId})")public int insert2(@Param("orderNo") String orderNo,@Param("userId") Long userId);

@Insert("insert into t_order_item(user_id,order_id,item_id) values(#{userId},#{orderId},#{itemId})")public int insertOrderItems(@Param("userId") Long userId,@Param("orderId") Long orderId,@Param("itemId") Long itemId);

@Select("select * from t_order where order_id > #{startValue}")

public ListfindList(Long startValue);

@Select("select * from t_order as a left join t_order_item as b on b.order_id = a.order_id left join t_order_config c on c.order_id = a.order_id where a.order_id = 460845380954202112 ")public ListfindAll();

}

2.test类

@SpringBootTest

class SpringbootShardingjdbcJavaconfigDemoApplicationTests {

@Autowired

private TOrderDao tOrderDao;

@Test

void contextLoads() {

// for (int i = 0; i < 2; i++) {

// int insert = tOrderDao.insert2( "11111",1L);

// System.out.println(insert);

// }

// List list = tOrderDao.findList(1L);

// System.out.println(list);

// tOrderDao.insertOrderItems(1L,460845380954202112L,1L);

List all = tOrderDao.findAll();

System.out.println(all);

}

}

其他:

官方网站:https://shardingsphere.apache.org/document/current/en/overview/

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值