preface

Apache ShardingSphere is an ecosystem of open source distributed database middleware solutions. It is composed of JDBC, Proxy and Sidecar (under planning), which are independent but can be deployed and used together. They all provide standardized data sharding, distributed transactions, and database governance functions, and can be applied to diverse application scenarios such as Java isomorphism, heterogeneous languages, and cloud native.

  • Apache ShardingSphere based ShardingJDBC 4.1.0 version of the source code analysis
  • Official Case Sources
  • purpose
    • Through the source code analysis of this chapter, deepen the understanding of ShardingJDBC configuration and use
    • Pave the way for subsequent source code analysis

A, configure ShardingRuleConfiguration fragmentation rules

1. Official cases

public final class ShardingDatabasesAndTablesConfigurationPrecise implements ExampleConfiguration { @Override public DataSource getDataSource() throws SQLException { ShardingRuleConfiguration shardingRuleConfig = new ShardingRuleConfiguration(); . / / the order table shard strategy shardingRuleConfig getTableRuleConfigs (). The add (getOrderTableRuleConfiguration ()); / / order_item table shard strategy shardingRuleConfig. GetTableRuleConfigs (). The add (getOrderItemTableRuleConfiguration ()); . / / the binding table order - order_item shardingRuleConfig getBindingTableGroups (). The add (" t_order, t_order_item "); . / / broadcast table t_address shardingRuleConfig getBroadcastTables (). The add (" t_address "); / / the default depots strategy shardingRuleConfig. SetDefaultDatabaseShardingStrategyConfig (new InlineShardingStrategyConfiguration (" user_id ",  "demo_ds_${user_id % 2}")); / / the default table strategy shardingRuleConfig. SetDefaultTableShardingStrategyConfig (new StandardShardingStrategyConfiguration (" order_id ",  new PreciseModuloShardingTableAlgorithm())); / / create a DataSource return ShardingDataSourceFactory. CreateDataSource (createDataSourceMap (), shardingRuleConfig, new Properties()); } // table sharding rule is not configured. Use the default fragmentation rules private static TableRuleConfiguration getOrderTableRuleConfiguration () {TableRuleConfiguration result = new TableRuleConfiguration("t_order", "demo_ds_${0.. 1}.t_order_${[0, 1]}"); result.setKeyGeneratorConfig(new KeyGeneratorConfiguration("SNOWFLAKE", "order_id", getProperties())); return result; } // order_item table rule, no sharding rule configured, Use the default fragmentation rules private static TableRuleConfiguration getOrderItemTableRuleConfiguration () {TableRuleConfiguration result = new TableRuleConfiguration("t_order_item", "demo_ds_${0.. 1}.t_order_item_${[0, 1]}"); result.setKeyGeneratorConfig(new KeyGeneratorConfiguration("SNOWFLAKE", "order_item_id", getProperties())); return result; } // dataSourceMap private static Map<String, DataSource> createDataSourceMap() { Map<String, DataSource> result = new HashMap<>(); result.put("demo_ds_0", DataSourceUtil.createDataSource("demo_ds_0")); result.put("demo_ds_1", DataSourceUtil.createDataSource("demo_ds_1")); return result; } private static Properties getProperties() {Properties result = new Properties(); result.setProperty("worker.id", "123"); return result; }}Copy the code

2, ShardingRuleConfiguration

ShardingRuleConfiguration class is the most commonly used configuration, configuration, support divided encryption configuration, reading and writing based on master-slave configuration, implementation RuleConfiguration marker interface.

@Getter
@Setter
public final class ShardingRuleConfiguration implements RuleConfiguration {
    private Collection<TableRuleConfiguration> tableRuleConfigs = new LinkedList<>();
    private Collection<String> bindingTableGroups = new LinkedList<>();
    private Collection<String> broadcastTables = new LinkedList<>();
    private String defaultDataSourceName;
    private ShardingStrategyConfiguration defaultDatabaseShardingStrategyConfig;
    private ShardingStrategyConfiguration defaultTableShardingStrategyConfig;
    private KeyGeneratorConfiguration defaultKeyGeneratorConfig;
    private Collection<MasterSlaveRuleConfiguration> masterSlaveRuleConfigs = new LinkedList<>();
    
    private EncryptRuleConfiguration encryptRuleConfig;
}
Copy the code
  • TableRuleConfigs: table rule configuration. You can set different sharding rules for different tables or use the default global sharding rules.
  • BindingTableGroups: Binding tables used for associative queries to prevent Cartesian products.
  • BroadcastTables: broadcastTables that exist on each node, such as t_ORDER and t_order_item.
  • DefaultDataSourceName: indicates the defaultDataSourceName.
  • DefaultDatabaseShardingStrategyConfig: default depots policy configuration.
  • DefaultTableShardingStrategyConfig: the default table policy configuration.
  • DefaultKeyGeneratorConfig: primary key generation configuration by default.
  • MasterSlaveRuleConfigs: master/slave rule configuration.
  • EncryptRuleConfig: Encryption rule configuration.

3, TableRuleConfiguration

TableRuleConfiguration Configures the actual data nodes (e.g. Demo_ds_ {0.. 1}. T_order_ {} [0, 1]). You can also configure specific sharding and primary key generation policies for logical tables.

@Getter
@Setter
public final class TableRuleConfiguration {
    private final String logicTable;
    private final String actualDataNodes;
    private ShardingStrategyConfiguration databaseShardingStrategyConfig;
    private ShardingStrategyConfiguration tableShardingStrategyConfig;
    private KeyGeneratorConfiguration keyGeneratorConfig;
    public TableRuleConfiguration(final String logicTable) {
        this(logicTable, null);
    }
    public TableRuleConfiguration(final String logicTable, final String actualDataNodes) {
        Preconditions.checkArgument(!Strings.isNullOrEmpty(logicTable), "LogicTable is required.");
        this.logicTable = logicTable;
        this.actualDataNodes = actualDataNodes;
    }
}
Copy the code
  • LogicTable: logical table name. For example, t_order.
  • ActualDataNodes: actual data node. For example: demo_ds_ {0.. T_order_ {[0, 1]}, representing the T_ORDER_0 and T_ORDER_1 tables of demo_DS_0 and t_ORDER_0 and T_ORDER_1 tables of demo_DS_1.
  • DatabaseShardingStrategyConfig: depots policy configuration.
  • TableShardingStrategyConfig: table strategy configuration.
  • KeyGeneratorConfig: primary key generation policy configuration.

Second, the shard ShardingStrategyConfiguration strategy configuration

ShardingStrategyConfiguration is a marker interface, inside what also have no. This policy configuration can be for branches or branches.

public interface ShardingStrategyConfiguration {
}
Copy the code

There are many tag interfaces in Sharding-JDBC for pass-through, and then different logic via Instanceof. For example ShardingStrategyFactory depending on the type of the actual ShardingStrategyConfiguration, create ShardingStrategy.

@NoArgsConstructor(access = AccessLevel.PRIVATE) public final class ShardingStrategyFactory { public static ShardingStrategy newInstance(final ShardingStrategyConfiguration shardingStrategyConfig) { if (shardingStrategyConfig instanceof StandardShardingStrategyConfiguration) { return new StandardShardingStrategy((StandardShardingStrategyConfiguration) shardingStrategyConfig); } if (shardingStrategyConfig instanceof InlineShardingStrategyConfiguration) { return new InlineShardingStrategy((InlineShardingStrategyConfiguration) shardingStrategyConfig); } if (shardingStrategyConfig instanceof ComplexShardingStrategyConfiguration) { return new ComplexShardingStrategy((ComplexShardingStrategyConfiguration) shardingStrategyConfig); } if (shardingStrategyConfig instanceof HintShardingStrategyConfiguration) { return new HintShardingStrategy((HintShardingStrategyConfiguration) shardingStrategyConfig); } return new NoneShardingStrategy(); }}Copy the code

ShardingStrategyConfiguration representative subdivision strategy configuration and runtime is converting configuration ShardingStrategy actual subdivision strategy.

Then look at the four ShardingStrategyConfiguration implementation, ignored the NoneShardingStrategyConfiguration here, because is empty.

1, InlineShardingStrategyConfiguration

InlineShardingStrategyConfiguration through expression (String) configuration, realize the shard strategy configuration.

@ Getter public final class InlineShardingStrategyConfiguration implements ShardingStrategyConfiguration {/ / shard listed private  final String shardingColumn; // Private final String algorithmExpression; public InlineShardingStrategyConfiguration(final String shardingColumn, final String algorithmExpression) { Preconditions.checkArgument(! Strings.isNullOrEmpty(shardingColumn), "ShardingColumn is required."); Preconditions.checkArgument(! Strings.isNullOrEmpty(algorithmExpression), "AlgorithmExpression is required."); this.shardingColumn = shardingColumn; this.algorithmExpression = algorithmExpression; }}Copy the code

Official case:

New InlineShardingStrategyConfiguration (” user_id “, “demo_ds_ ${user_id % 2}”) said: For the user_id column, if user_id % 2 == 0, enter the demo_ds_0 data source; If user_id % 2 == 1, enter the demo_DS_1 data source.

2, StandardShardingStrategyConfiguration

StandardShardingStrategyConfiguration by configuring PreciseShardingAlgorithm precise subdivision algorithm and RangeShardingAlgorithm interval subdivision algorithm (optional), to realize subdivision strategy configuration.

@ Getter public final class StandardShardingStrategyConfiguration implements ShardingStrategyConfiguration {/ / shard private final String shardingColumn; Private final PreciseShardingAlgorithm PreciseShardingAlgorithm; Private Final RangeShardingAlgorithm RangeShardingAlgorithm; public StandardShardingStrategyConfiguration(final String shardingColumn, final PreciseShardingAlgorithm preciseShardingAlgorithm) { this(shardingColumn, preciseShardingAlgorithm, null); } public StandardShardingStrategyConfiguration(final String shardingColumn, final PreciseShardingAlgorithm preciseShardingAlgorithm, final RangeShardingAlgorithm rangeShardingAlgorithm) { Preconditions.checkArgument(! Strings.isNullOrEmpty(shardingColumn), "ShardingColumns is required."); Preconditions.checkNotNull(preciseShardingAlgorithm, "PreciseShardingAlgorithm is required."); this.shardingColumn = shardingColumn; this.preciseShardingAlgorithm = preciseShardingAlgorithm; this.rangeShardingAlgorithm = rangeShardingAlgorithm; }}Copy the code

PreciseShardingAlgorithm

PreciseShardingAlgorithm For PreciseShardingValue, which is used to process = or in.

public interface PreciseShardingAlgorithm<T extends Comparable<? >> extends ShardingAlgorithm { String doSharding(Collection<String> availableTargetNames, PreciseShardingValue<T> shardingValue); }Copy the code

PreciseShardingValue holds logical tables, column names, and corresponding column values.

public final class PreciseShardingValue<T extends Comparable<? >> implements ShardingValue {// Private final String logicTableName; Private final String columnName; // value private final T value; }Copy the code

Official case:

Determine which actual table to fall into according to whether the table name ends with a fragment key divided by 2 modulo.

public final class PreciseModuloShardingTableAlgorithm implements PreciseShardingAlgorithm<Long> { @Override public String doSharding(final Collection<String> tableNames, final PreciseShardingValue<Long> shardingValue) { for (String each : tableNames) { if (each.endsWith(shardingValue.getValue() % 2 + "")) { return each; } } throw new UnsupportedOperationException(); }}Copy the code

RangeShardingAlgorithm

RangeShardingAlgorithm shards between and, >, <.

public interface RangeShardingAlgorithm<T extends Comparable<? >> extends ShardingAlgorithm { Collection<String> doSharding(Collection<String> availableTargetNames, RangeShardingValue<T> shardingValue); }Copy the code

RangeShardingValue holds logical table names, column names, and ranges.

public final class RangeShardingValue<T extends Comparable<? >> implements ShardingValue { private final String logicTableName; private final String columnName; private final Range<T> valueRange; }Copy the code

Official case:

PreciseModuloShardingDatabaseAlgorithm according to user_id except two modulus depots, RangeModuloShardingDatabaseAlgorithm according to user_id interval table.

public final class ShardingDatabasesConfigurationRange implements ExampleConfiguration { @Override public DataSource getDataSource() throws SQLException { ShardingRuleConfiguration shardingRuleConfig = new ShardingRuleConfiguration(); shardingRuleConfig.getTableRuleConfigs().add(getOrderTableRuleConfiguration()); shardingRuleConfig.getTableRuleConfigs().add(getOrderItemTableRuleConfiguration()); shardingRuleConfig.getBroadcastTables().add("t_address"); shardingRuleConfig.setDefaultDatabaseShardingStrategyConfig( new StandardShardingStrategyConfiguration("user_id" // Precise subdivision strategy user_id modulus, new PreciseModuloShardingDatabaseAlgorithm () / / interval subdivision strategy, new RangeModuloShardingDatabaseAlgorithm())); Properties properties = new Properties(); properties.put("sql.show", true); return ShardingDataSourceFactory.createDataSource(createDataSourceMap(), shardingRuleConfig, properties); } private static TableRuleConfiguration getOrderTableRuleConfiguration() { TableRuleConfiguration result = new TableRuleConfiguration("t_order"); result.setKeyGeneratorConfig(new KeyGeneratorConfiguration("SNOWFLAKE", "order_id", getProperties())); return result; } private static TableRuleConfiguration getOrderItemTableRuleConfiguration() { TableRuleConfiguration result = new TableRuleConfiguration("t_order_item"); result.setKeyGeneratorConfig(new KeyGeneratorConfiguration("SNOWFLAKE", "order_item_id", getProperties())); return result; } private static Map<String, DataSource> createDataSourceMap() { Map<String, DataSource> result = new HashMap<>(); result.put("demo_ds_0", DataSourceUtil.createDataSource("demo_ds_0")); result.put("demo_ds_1", DataSourceUtil.createDataSource("demo_ds_1")); return result; } private static Properties getProperties() { Properties result = new Properties(); result.setProperty("worker.id", "123"); return result; }}Copy the code
  • If the [1,5] interval contains an input interval, return the demo_ds_0 data source;
  • If the [6,10] interval contains an input interval, the demo_ds_1 data source is returned;
  • If the [1,10] interval contains an input interval, all data sources are returned;
  • Other throw exceptions.
public final class RangeModuloShardingDatabaseAlgorithm implements RangeShardingAlgorithm<Integer> { @Override public Collection<String> doSharding(final Collection<String> databaseNames, final RangeShardingValue<Integer> shardingValueRange) { Set<String> result = new LinkedHashSet<>(); if (Range.closed(1, 5).encloses(shardingValueRange.getValueRange())) { for (String each : databaseNames) { if (each.endsWith("0")) { result.add(each); } } } else if (Range.closed(6, 10).encloses(shardingValueRange.getValueRange())) { for (String each : databaseNames) { if (each.endsWith("1")) { result.add(each); } } } else if (Range.closed(1, 10).encloses(shardingValueRange.getValueRange())) { result.addAll(databaseNames); } else { throw new UnsupportedOperationException(); } return result; }}Copy the code

This is just a case study, and is not configured this way.

The result of this configuration is to insert demo_ds_0 and demo_ds_1 according to user_id % 2, with 2, 4, 6, 8, 10 in demo_DS_0 and 1, 3, 5, 7, 9 in demo_ds_1.

SELECT I.* FROM t_order o, T_order_item I WHERE o.order_id = i.order_id AND O.usser_id BETWEEN 1 AND 5

3, HintShardingStrategyConfiguration

HintShardingStrategyConfiguration suggested shard strategy configuration. No specified HintShardingStrategyConfiguration building is a field which shard. Implied sharding is not performed by parsing the values of fields in the SQL (i.e. User_id =? Or user_id >? And this? Represents the value to implement the sharding algorithm), which needs to be set by HintManager (ThreadLocal) to implement the sharding algorithm.

@Getter public final class HintShardingStrategyConfiguration implements ShardingStrategyConfiguration { private final HintShardingAlgorithm shardingAlgorithm; public HintShardingStrategyConfiguration(final HintShardingAlgorithm shardingAlgorithm) { Preconditions.checkNotNull(shardingAlgorithm, "ShardingAlgorithm is required."); this.shardingAlgorithm = shardingAlgorithm; }}Copy the code

HintShardingAlgorithm indicates the sharding algorithm interface.

public interface HintShardingAlgorithm<T extends Comparable<? >> extends ShardingAlgorithm { Collection<String> doSharding(Collection<String> availableTargetNames, HintShardingValue<T> shardingValue); }Copy the code

HintShardingValue holds logical table names, column names, and a list of values that are put in through HintManager.

public final class HintShardingValue<T extends Comparable<? >> implements ShardingValue { private final String logicTableName; private final String columnName; private final Collection<T> values; }Copy the code

Official case:

ModuloHintShardingAlgorithm or according to in addition to take more than 2 into the actual table name or identification.

public final class ModuloHintShardingAlgorithm implements HintShardingAlgorithm<Long> { @Override public Collection<String> doSharding(final Collection<String> availableTargetNames, final HintShardingValue<Long> shardingValue) { Collection<String> result = new ArrayList<>(); for (String each : availableTargetNames) { for (Long value : shardingValue.getValues()) { if (each.endsWith(String.valueOf(value % 2))) { result.add(each); } } } return result; }}Copy the code

Use Hint subdivision, need before use by HintManager setting shard values, the value in the sharding – will add HintShardingValue JDBC processing process, to ModuloHintShardingAlgorithm.

private static void processWithHintValue(final DataSource dataSource) throws SQLException {
    try (HintManager hintManager = HintManager.getInstance();
         Connection connection = dataSource.getConnection();
         Statement statement = connection.createStatement()) {
        setHintValue(hintManager);
        statement.execute("select * from t_order");
        statement.execute("SELECT i.* FROM t_order o, t_order_item i WHERE o.order_id = i.order_id");
        statement.execute("select * from t_order_item");
        statement.execute("INSERT INTO t_order (user_id, address_id, status) VALUES (1, 1, 'init')");
    }
}
private static void setHintValue(final HintManager hintManager) {
	switch (TYPE) {
	    case DATABASE_TABLES:
	        hintManager.addDatabaseShardingValue("t_order", 1L);
	        hintManager.addTableShardingValue("t_order", 1L);
	        return;
	    case DATABASE_ONLY:
	        hintManager.setDatabaseShardingValue(1L);
	        return;
	    case MASTER_ONLY:
	        hintManager.setMasterRouteOnly();
	        return;
	    default:
	        throw new UnsupportedOperationException("unsupported type");
	}
}
Copy the code

More on Hint sharding, read on later.

4, ComplexShardingStrategyConfiguration

ComplexShardingStrategyConfiguration composite subdivision strategy configuration. In multiple fields, setting ComplexKeysShardingAlgorithm subdivision algorithm and realize according to the multiple shard key set subdivision strategy.

@Getter public final class ComplexShardingStrategyConfiguration implements ShardingStrategyConfiguration { private final  String shardingColumns; private final ComplexKeysShardingAlgorithm shardingAlgorithm; public ComplexShardingStrategyConfiguration(final String shardingColumns, final ComplexKeysShardingAlgorithm shardingAlgorithm) { Preconditions.checkArgument(! Strings.isNullOrEmpty(shardingColumns), "ShardingColumns is required."); Preconditions.checkNotNull(shardingAlgorithm, "ShardingAlgorithm is required."); this.shardingColumns = shardingColumns; this.shardingAlgorithm = shardingAlgorithm; }}Copy the code

Shard ComplexKeysShardingAlgorithm according to ComplexKeysShardingValue execution.

public interface ComplexKeysShardingAlgorithm<T extends Comparable<? >> extends ShardingAlgorithm { Collection<String> doSharding(Collection<String> availableTargetNames, ComplexKeysShardingValue<T> shardingValue); }Copy the code

ComplexKeysShardingValue holds mappings between logical table names, field-shard values, and field-shard ranges.

@RequiredArgsConstructor @Getter @ToString public final class ComplexKeysShardingValue<T extends Comparable<? >> implements ShardingValue { private final String logicTableName; private final Map<String, Collection<T>> columnNameAndShardingValuesMap; private final Map<String, Range<T>> columnNameAndRangeValuesMap; }Copy the code

Third, MasterSlaveRuleConfiguration

The rules of master-slave MasterSlaveRuleConfiguration configuration.

@Getter public final class MasterSlaveRuleConfiguration implements RuleConfiguration { private final String name; private final String masterDataSourceName; private final List<String> slaveDataSourceNames; private final LoadBalanceStrategyConfiguration loadBalanceStrategyConfiguration; public MasterSlaveRuleConfiguration(final String name, final String masterDataSourceName, final List<String> slaveDataSourceNames) { this(name, masterDataSourceName, slaveDataSourceNames, null); } public MasterSlaveRuleConfiguration(final String name, final String masterDataSourceName, final List<String> slaveDataSourceNames, final LoadBalanceStrategyConfiguration loadBalanceStrategyConfiguration) { Preconditions.checkArgument(! Strings.isNullOrEmpty(name), "Name is required."); Preconditions.checkArgument(! Strings.isNullOrEmpty(masterDataSourceName), "MasterDataSourceName is required."); Preconditions.checkArgument(null ! = slaveDataSourceNames && ! slaveDataSourceNames.isEmpty(), "SlaveDataSourceNames is required."); this.name = name; this.masterDataSourceName = masterDataSourceName; this.slaveDataSourceNames = slaveDataSourceNames; this.loadBalanceStrategyConfiguration = loadBalanceStrategyConfiguration; }}Copy the code
  • Name: MasterSlaveRuleConfiguration logical data source name.
  • MasterDataSourceName: data source name of the primary database.
  • SlaveDataSourceNames: Data source names of all slave libraries corresponding to the master library.
  • LoadBalanceStrategyConfiguration: master-slave load balancing strategy.

Official case:

public final class ShardingMasterSlaveConfigurationPrecise implements ExampleConfiguration { @Override public DataSource  getDataSource() throws SQLException { ShardingRuleConfiguration shardingRuleConfig = new ShardingRuleConfiguration(); shardingRuleConfig.getTableRuleConfigs().add(getOrderTableRuleConfiguration()); shardingRuleConfig.getTableRuleConfigs().add(getOrderItemTableRuleConfiguration()); shardingRuleConfig.getBindingTableGroups().add("t_order, t_order_item"); shardingRuleConfig.getBroadcastTables().add("t_address"); shardingRuleConfig.setDefaultDatabaseShardingStrategyConfig(new StandardShardingStrategyConfiguration("user_id", new PreciseModuloShardingDatabaseAlgorithm())); shardingRuleConfig.setDefaultTableShardingStrategyConfig(new StandardShardingStrategyConfiguration("order_id", new PreciseModuloShardingTableAlgorithm())); shardingRuleConfig.setMasterSlaveRuleConfigs(getMasterSlaveRuleConfigurations()); return ShardingDataSourceFactory.createDataSource(createDataSourceMap(), shardingRuleConfig, new Properties()); } private static TableRuleConfiguration getOrderTableRuleConfiguration() { TableRuleConfiguration result = new TableRuleConfiguration("t_order", "ds_${0.. 1}.t_order_${[0, 1]}"); result.setKeyGeneratorConfig(new KeyGeneratorConfiguration("SNOWFLAKE", "order_id", getProperties())); return result; } private static TableRuleConfiguration getOrderItemTableRuleConfiguration() { TableRuleConfiguration result = new TableRuleConfiguration("t_order_item", "ds_${0.. 1}.t_order_item_${[0, 1]}"); result.setKeyGeneratorConfig(new KeyGeneratorConfiguration("SNOWFLAKE", "order_item_id", getProperties())); return result; } / / master-slave configuration private static List < MasterSlaveRuleConfiguration > getMasterSlaveRuleConfigurations () { MasterSlaveRuleConfiguration masterSlaveRuleConfig1 = new MasterSlaveRuleConfiguration("ds_0", "demo_ds_master_0", Arrays.asList("demo_ds_master_0_slave_0", "demo_ds_master_0_slave_1")); MasterSlaveRuleConfiguration masterSlaveRuleConfig2 = new MasterSlaveRuleConfiguration("ds_1", "demo_ds_master_1", Arrays.asList("demo_ds_master_1_slave_0", "demo_ds_master_1_slave_1")); return Lists.newArrayList(masterSlaveRuleConfig1, masterSlaveRuleConfig2); } private static Map<String, DataSource> createDataSourceMap() {final Map<String, DataSource> result = new HashMap<>(); result.put("demo_ds_master_0", DataSourceUtil.createDataSource("demo_ds_master_0")); result.put("demo_ds_master_0_slave_0", DataSourceUtil.createDataSource("demo_ds_master_0_slave_0")); result.put("demo_ds_master_0_slave_1", DataSourceUtil.createDataSource("demo_ds_master_0_slave_1")); result.put("demo_ds_master_1", DataSourceUtil.createDataSource("demo_ds_master_1")); result.put("demo_ds_master_1_slave_0", DataSourceUtil.createDataSource("demo_ds_master_1_slave_0")); result.put("demo_ds_master_1_slave_1", DataSourceUtil.createDataSource("demo_ds_master_1_slave_1")); return result; } private static Properties getProperties() { Properties result = new Properties(); result.setProperty("worker.id", "123"); return result; }}Copy the code

Spi-based configuration

Sharding-jdbc uses the SPI mechanism of JDK to facilitate users to expand according to actual requirements. How to combine Sharding – JDBC with SPI? We will talk about it later if we have the opportunity.

TypeBasedSPIConfiguration is to configure the base class, need to configure the type (TypeBasedSPI interface to get the type) and the properties.

public abstract class TypeBasedSPIConfiguration {
    private final String type;
    private final Properties properties;
    public TypeBasedSPIConfiguration(final String type) {
        this(type, null);
    }
    public TypeBasedSPIConfiguration(final String type, final Properties properties) {
        Preconditions.checkArgument(!Strings.isNullOrEmpty(type), "Type is required.");
        this.type = type;
        this.properties = null == properties ? new Properties() : properties;
    }
}
Copy the code

Runtime, by matching TypeBasedSPIConfiguration type field and TypeBasedSPI getType method return value, to determine the actual use the implementation class.

public interface TypeBasedSPI {
    String getType();
    Properties getProperties();
    void setProperties(Properties properties);
}
Copy the code

1, CenterConfiguration

CenterConfiguration is the configuration that implements the Sharding-JDBC integration configuration (registry) center.

@ Getter @ Setter public final class CenterConfiguration extends TypeBasedSPIConfiguration {/ / config_center said allocation center, Registry_center Specifies the registry. Private String orchestrationType; Private String serverLists; // namespace private String namespace; public CenterConfiguration(final String type) { super(type); } public CenterConfiguration(final String type, final Properties properties) { super(type, properties); }}Copy the code

CenterRepository is the interface that configuration (registry) centers need to implement, that is, add, delete, watch operations.

public interface CenterRepository extends TypeBasedSPI {
    void init(CenterConfiguration config);
    String get(String key);
    void persist(String key, String value);
    void close();
    List<String> getChildrenKeys(String key);
    void watch(String key, DataChangedEventListener dataChangedEventListener);
}
Copy the code

ConfigCenterRepository is an interface implemented by middleware that provides only configuration center functionality. It simply inherits the CenterRepository interface and does not extend other required implementations.

public interface ConfigCenterRepository extends CenterRepository {
}
Copy the code

RegistryCenterRepository is an interface required by middleware that provides not only configuration centers but also registry functions, extending the persistEphemeral method. Currently, only Zookeeper and Etcd implement this interface. For Zookeeper, temporary nodes are created.

public interface RegistryCenterRepository extends CenterRepository {
    void persistEphemeral(String key, String value);
}
Copy the code

It supports Apollo, Nacos, Zookeeper, and Etcd. The corresponding source code is in the Sharding-orchestration module, the subsequent opportunity to further understand.

2, EncryptorRuleConfiguration

Encryption to decrypt EncryptorRuleConfiguration configuration support fields, such as the user phone number desensitization, and so on, the official case with reference to: Org. Apache. Shardingsphere. Example. Encrypt. Table. Raw. JDBC. Config. EncryptDatabasesConfiguration# getDataSource.

@Getter public final class EncryptorRuleConfiguration extends TypeBasedSPIConfiguration { public EncryptorRuleConfiguration(final String type, final Properties properties) { super(type, properties); }}Copy the code

All encryption algorithms need to implement the Encryptor interface to provide encryption and decryption implementation.

Public interface Encryptor extends TypeBasedSPI {// Initializes void init(); // Encrypt text to ciphertext String (Object plaintext); // Object decrypt(String ciphertext); }Copy the code

3, KeyGeneratorConfiguration

KeyGeneratorConfiguration used to configure the primary key generation strategy in ShardingRuleConfiguration configuration, you can set the global default, also can be in a form custom.

public final class KeyGeneratorConfiguration extends TypeBasedSPIConfiguration { private final String column; public KeyGeneratorConfiguration(final String type, final String column) { super(type); Preconditions.checkArgument(! Strings.isNullOrEmpty(column), "Column is required."); this.column = column; } public KeyGeneratorConfiguration(final String type, final String column, final Properties properties) { super(type, properties); Preconditions.checkArgument(! Strings.isNullOrEmpty(column), "Column is required."); this.column = column; }}Copy the code

You can see KeyGeneratorConfiguration is aimed at a field configuration.

ShardingKeyGenerator is the interface that each primary key generation policy needs to implement. Currently, UUID and Snowflake algorithm are officially supported for primary key generation.

public interface ShardingKeyGenerator extends TypeBasedSPI { Comparable<? > generateKey(); }Copy the code

4, LoadBalanceStrategyConfiguration

LoadBalanceStrategyConfiguration in configuration master-slave situation, support the definition of load balancing strategy.

@Getter public final class LoadBalanceStrategyConfiguration extends TypeBasedSPIConfiguration { public LoadBalanceStrategyConfiguration(final String type) { super(type); } public LoadBalanceStrategyConfiguration(final String type, final Properties properties) { super(type, properties); }}Copy the code

All load balancing strategy to implement MasterSlaveLoadBalanceAlgorithm interface, realize getDataSource methods select a data source to return from the master-slave data source.

Public interface MasterSlaveLoadBalanceAlgorithm extends TypeBasedSPI {/ / the name - master-slave configuration data source name / / masterDataSourceName - String getDataSource(String name, String masterDataSourceName, List<String> slaveDataSourceNames); }Copy the code

conclusion

  • ShardingRuleConfigurationandTableRuleConfigurationAre the two most important configuration classes in ShardingJDBC, corresponding to the runtimeShardingRuleandTableRule.
  • ShardingRuleConfigurationYou can configure the default database and table policy,TableRuleConfigurationYou can customize the database and table strategy for the table.
  • Through the SPI mechanism, users can customize some reserved extension points. Such as desensitization rules, primary key policies, etc.