/*
* Copyright 1999-2015 dangdang.com.
* <p>
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
* </p>
*/
package com.dangdang.ddframe.rdb.sharding.api.rule;
import com.dangdang.ddframe.rdb.sharding.api.strategy.database.DatabaseShardingStrategy;
import com.dangdang.ddframe.rdb.sharding.api.strategy.database.NoneDatabaseShardingAlgorithm;
import com.dangdang.ddframe.rdb.sharding.api.strategy.table.NoneTableShardingAlgorithm;
import com.dangdang.ddframe.rdb.sharding.api.strategy.table.TableShardingStrategy;
import com.dangdang.ddframe.rdb.sharding.exception.ShardingJdbcException;
import com.dangdang.ddframe.rdb.sharding.id.generator.IdGenerator;
import com.google.common.base.Optional;
import com.google.common.base.Preconditions;
import com.google.common.collect.Sets;
import lombok.Getter;
import lombok.RequiredArgsConstructor;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.Set;
import java.util.TreeSet;
/**
* 分库分表规则配置对象.
*
* @author zhangliang
*/
@Getter
public final class ShardingRule {
private final DataSourceRule dataSourceRule;
private final Collection<TableRule> tableRules;
private final Collection<BindingTableRule> bindingTableRules;
private final DatabaseShardingStrategy databaseShardingStrategy;
private final TableShardingStrategy tableShardingStrategy;
/**
* 全属性构造器.
*
* <p>用于Spring非命名空间的配置.</p>
*
* <p>未来将改为private权限, 不在对外公开, 不建议使用非Spring命名空间的配置.</p>
*
* @deprecated 未来将改为private权限, 不在对外公开, 不建议使用非Spring命名空间的配置.
*/
@Deprecated
public ShardingRule(
final DataSourceRule dataSourceRule, final Collection<TableRule> tableRules, final Collection<BindingTableRule> bindingTableRules,
final DatabaseShardingStrategy databaseShardingStrategy, final TableShardingStrategy tableShardingStrategy) {
Preconditions.checkNotNull(dataSourceRule);
this.dataSourceRule = dataSourceRule;
this.tableRules = null == tableRules ? Collections.<TableRule>emptyList() : tableRules;
this.bindingTableRules = null == bindingTableRules ? Collections.<BindingTableRule>emptyList() : bindingTableRules;
this.databaseShardingStrategy = null == databaseShardingStrategy ? new DatabaseShardingStrategy(
Collections.<String>emptyList(), new NoneDatabaseShardingAlgorithm()) : databaseShardingStrategy;
this.tableShardingStrategy = null == tableShardingStrategy ? new TableShardingStrategy(
Collections.<String>emptyList(), new NoneTableShardingAlgorithm()) : tableShardingStrategy;
}
/**
* 获取表规则配置对象构建器.
*
* @return 分片规则配置对象构建器
*/
public static ShardingRuleBuilder builder() {
return new ShardingRuleBuilder();
}
/**
* 试着根据逻辑表名称查找分片规则.
*
* @param logicTableName 逻辑表名称
* @return 该逻辑表的分片规则
*/
public Optional<TableRule> tryFindTableRule(final String logicTableName) {
for (TableRule each : tableRules) {
if (each.getLogicTable().equalsIgnoreCase(logicTableName)) {
return Optional.of(each);
}
}
return Optional.absent();
}
/**
* 根据逻辑表名找到指定分片规则.
*
* @param logicTableName 逻辑表名称
* @return 该逻辑表的分片规则
*/
public TableRule findTableRule(final String logicTableName) {
Optional<TableRule> tableRuleOptional = tryFindTableRule(logicTableName);
if (tableRuleOptional.isPresent()) {
return tableRuleOptional.get();
}
throw new ShardingJdbcException(String.format("%s does not exist in ShardingRule", logicTableName));
}
/**
* 获取数据库分片策略.
*
* <p>
* 根据表规则配置对象获取分片策略, 如果获取不到则获取默认分片策略.
* </p>
*
* @param tableRule 表规则配置对象
* @return 数据库分片策略
*/
public DatabaseShardingStrategy getDatabaseShardingStrategy(final TableRule tableRule) {
DatabaseShardingStrategy result = tableRule.getDatabaseShardingStrategy();
if (null == result) {
result = databaseShardingStrategy;
}
Preconditions.checkNotNull(result, "no database sharding strategy");
return result;
}
/**
* 获取表分片策略.
*
* <p>
* 根据表规则配置对象获取分片策略, 如果获取不到则获取默认分片策略.
* </p>
*
* @param tableRule 表规则配置对象
* @return 表分片策略
*/
public TableShardingStrategy getTableShardingStrategy(final TableRule tableRule) {
TableShardingStrategy result = tableRule.getTableShardingStrategy();
if (null == result) {
result = tableShardingStrategy;
}
Preconditions.checkNotNull(result, "no table sharding strategy");
return result;
}
/**
* 判断逻辑表名称集合是否全部属于Binding表.
*
* @param logicTables 逻辑表名称集合
* @return 是否全部属于Binding表
*/
public boolean isAllBindingTables(final Collection<String> logicTables) {
Collection<String> bindingTables = filterAllBindingTables(logicTables);
return !bindingTables.isEmpty() && bindingTables.containsAll(logicTables);
}
/**
* 过滤出所有的Binding表名称.
*
* @param logicTables 逻辑表名称集合
* @return 所有的Binding表名称集合
*/
public Collection<String> filterAllBindingTables(final Collection<String> logicTables) {
if (logicTables.isEmpty()) {
return Collections.emptyList();
}
Optional<BindingTableRule> bindingTableRule = findBindingTableRule(logicTables);
if (!bindingTableRule.isPresent()) {
return Collections.emptyList();
}
Collection<String> result = new ArrayList<>(bindingTableRule.get().getAllLogicTables());
result.retainAll(logicTables);
return result;
}
private Optional<BindingTableRule> findBindingTableRule(final Collection<String> logicTables) {
for (String each : logicTables) {
Optional<BindingTableRule> result = findBindingTableRule(each);
if (result.isPresent()) {
return result;
}
}
return Optional.absent();
}
/**
* 根据逻辑表名称获取binding表配置的逻辑表名称集合.
*
* @param logicTable 逻辑表名称
* @return binding表配置的逻辑表名称集合
*/
public Optional<BindingTableRule> findBindingTableRule(final String logicTable) {
for (BindingTableRule each : bindingTableRules) {
if (each.hasLogicTable(logicTable)) {
return Optional.of(each);
}
}
return Optional.absent();
}
/**
* 获取所有的分片列名.
*
* @param tableName 表名
* @return 分片列名集合
*/
public Collection<String> getAllShardingColumns(final String tableName) {
Set<String> result = new TreeSet<>(String.CASE_INSENSITIVE_ORDER);
result.addAll(databaseShardingStrategy.getShardingColumns());
result.addAll(tableShardingStrategy.getShardingColumns());
for (TableRule each : tableRules) {
if (!each.getLogicTable().equalsIgnoreCase(tableName)) {
continue;
}
if (null != each.getDatabaseShardingStrategy()) {
result.addAll(each.getDatabaseShardingStrategy().getShardingColumns());
}
if (null != each.getTableShardingStrategy()) {
result.addAll(each.getTableShardingStrategy().getShardingColumns());
}
}
return result;
}
/**
* 获取所有需要自增的列名.
*
* @param tableName 表名
* @return 自增列
*/
public Collection<String> getAutoIncrementColumns(final String tableName) {
for (TableRule each : tableRules) {
if (!each.getLogicTable().equalsIgnoreCase(tableName)) {
continue;
}
return Sets.newLinkedHashSet(each.getAutoIncrementColumnMap().keySet());
}
return Collections.emptySet();
}
/**
* 分片规则配置对象构建器.
*/
@RequiredArgsConstructor
public static class ShardingRuleBuilder {
private DataSourceRule dataSourceRule;
private Collection<TableRule> tableRules;
private Collection<BindingTableRule> bindingTableRules;
private DatabaseShardingStrategy databaseShardingStrategy;
private TableShardingStrategy tableShardingStrategy;
private Class<? extends IdGenerator> idGeneratorClass;
/**
* 构建数据源配置规则.
*
* @param dataSourceRule 数据源配置规则
* @return 分片规则配置对象构建器
*/
public ShardingRuleBuilder dataSourceRule(final DataSourceRule dataSourceRule) {
this.dataSourceRule = dataSourceRule;
return this;
}
/**
* 构建表配置规则.
*
* @param tableRules 表配置规则
* @return 分片规则配置对象构建器
*/
public ShardingRuleBuilder tableRules(final Collection<TableRule> tableRules) {
this.tableRules = tableRules;
return this;
}
/**
* 构建绑定表配置规则.
*
* @param bindingTableRules 绑定表配置规则
* @return 分片规则配置对象构建器
*/
public ShardingRuleBuilder bindingTableRules(final Collection<BindingTableRule> bindingTableRules) {
this.bindingTableRules = bindingTableRules;
return this;
}
/**
* 构建默认分库策略.
*
* @param databaseShardingStrategy 默认分库策略
* @return 分片规则配置对象构建器
*/
public ShardingRuleBuilder databaseShardingStrategy(final DatabaseShardingStrategy databaseShardingStrategy) {
this.databaseShardingStrategy = databaseShardingStrategy;
return this;
}
/**
* 构建数据源分片规则.
*
* @param tableShardingStrategy 默认分表策略
* @return 分片规则配置对象构建器
*/
public ShardingRuleBuilder tableShardingStrategy(final TableShardingStrategy tableShardingStrategy) {
this.tableShardingStrategy = tableShardingStrategy;
return this;
}
/**
* 构建默认id生成器.
*
* @param idGeneratorClass 默认的Id生成器
* @return 分片规则配置对象构建器
*/
public ShardingRuleBuilder idGenerator(final Class<? extends IdGenerator> idGeneratorClass) {
this.idGeneratorClass = idGeneratorClass;
return this;
}
/**
* 构建分片规则配置对象.
*
* @return 分片规则配置对象
*/
public ShardingRule build() {
ShardingRule result = new ShardingRule(dataSourceRule, tableRules, bindingTableRules, databaseShardingStrategy, tableShardingStrategy);
if (null == idGeneratorClass) {
return result;
}
for (TableRule each : tableRules) {
each.fillIdGenerator(idGeneratorClass);
}
return result;
}
}
}