Aperçu
Les métadonnées sont les données qui constituent les données. En termes de base de données, toutes les données qui décrivent la base de données sont des métadonnées. Les noms de colonne, les noms de base de données, les noms d’utilisateur, les noms de table, etc., et les tables de bibliothèque de personnalisation des données qui stockent des informations sur les objets de la base de données sont des métadonnées. Les fonctions de base de ShardingSphere telles que le sharding, le chiffrement et le déchiffrement des données sont toutes basées sur les métadonnées de la base de données.
Cela montre que les métadonnées sont au cœur du système ShardingSphere et sont également les données de base de chaque middleware ou composant lié au stockage de données. Avec l’injection de métadonnées, cela équivaut à avoir un centre névralgique pour l’ensemble du système, qui peut être associé à des métadonnées pour effectuer des opérations personnalisées sur des bibliothèques, des tables et des colonnes, telles que le sharding, le cryptage des données, la réécriture SQL, etc.
Pour le processus de chargement des métadonnées ShardingSphere, il est d’abord nécessaire de clarifier le type et la hiérarchie des métadonnées dans ShardingSphere. Les métadonnées dans ShardingSphere sont principalement basées sur le ShardingSphereMetaData
, dont le noyau est le ShardingSphereSchema
, qui correspond aux métadonnées de la base de données et constitue également l’objet de niveau supérieur des métadonnées de la source de données. La structure des métadonnées de la base de données dans ShardingSphere est illustrée ci-dessous, pour chaque couche, les données de la couche supérieure proviennent de l’assemblage des données de la couche inférieure, nous utilisons donc la hiérarchie ascendante suivante pour analyser une par une.
ColumMetaData et IndexMetaData
ColumMetaData
et IndexMetaData
sont les éléments de base qui composent TableMetaData
. Dans ce qui suit, nous analyserons séparément la structure des deux types de métadonnées et le processus de chargement. ColumMetaData
a la structure principale suivante :
public final class ColumnMetaData {
// private final String name;
// private final int dataType;
// private final boolean primaryKey;
// private final boolean generated;
// private final boolean caseSensitive;
}
Le processus de chargement est principalement encapsulé dans le org.apache.shardingsphere.infra.metadata.schema.builder.loader.ColumnMetaDataLoader#load
méthode, et son processus principal consiste à charger les métadonnées de toutes les colonnes sous un nom de table en obtenant les métadonnées correspondant au nom de la table via le lien de la base de données.
Le code de base est le suivant :
/**
* Load column meta data list.
* * @param connection connection
* @param tableNamePattern table name pattern
* @param databaseType database type
* @return column meta data list
* @throws SQLException SQL exception
*/
public static Collection<ColumnMetaData> load(final Connection connection,
final String tableNamePattern, final DatabaseType databaseType) throws SQLException {
Collection<ColumnMetaData> result = new LinkedList<>();
Collection<String> primaryKeys = loadPrimaryKeys(connection, tableNamePattern);
List<String> columnNames = new ArrayList<>();
List<Integer> columnTypes = new ArrayList<>();
List<String> columnTypeNames = new ArrayList<>();
List<Boolean> isPrimaryKeys = new ArrayList<>();
List<Boolean> isCaseSensitives = new ArrayList<>();
try (ResultSet resultSet =
connection.getMetaData().getColumns(connection.getCatalog(), connection.getSchema(),
tableNamePattern, "%")) {
while (resultSet.next()) {
String tableName = resultSet.getString(TABLE_NAME);
if (Objects.equals(tableNamePattern, tableName)) {
String columnName = resultSet.getString(COLUMN_NAME);
columnTypes.add(resultSet.getInt(DATA_TYPE));
columnTypeNames.add(resultSet.getString(TYPE_NAME));
isPrimaryKeys.add(primaryKeys.contains(columnName));
columnNames.add(columnName);
}
}
}
try (Statement statement = connection.createStatement(); ResultSet resultSet =
statement.executeQuery(generateEmptyResultSQL(tableNamePattern, databaseType))) {
for (int i = 0; i < columnNames.size(); i++)
isCaseSensitives.add(resultSet.getMetaData().isCaseSensitive(resultSet.findColumn(columnNames.get(i))));
result.add(new ColumnMetaData(columnNames.get(i), columnTypes.get(i),
isPrimaryKeys.get(i),
resultSet.getMetaData().isAutoIncrement(i + 1),
isCaseSensitives.get(i)));
}
}
return result;
}
IndexMetaData
est le nom de l’index dans la table, il n’y a donc pas de propriétés structurelles complexes, juste un nom. Au lieu d’entrer dans les détails, nous nous concentrons plutôt sur le processus de chargement. Son processus de chargement est similaire à celui d’une colonne, et le processus principal est dans le org.apache.shardingsphere.infra.metadata.schema.builder.loader.IndexMetaDataLoader#load
méthode.
Le processus de base passe également par le lien de la base de données pour obtenir le noyau IndexMetaData
dans le IndexInfo
l’organisation de la base de données et des métadonnées de table pertinentes, et le code de mise en œuvre est le suivant :
public static Collection<IndexMetaData> load(final Connection connection,
final String table)
throws SQLException {
Collection<IndexMetaData> result = new HashSet<>();
try (ResultSet resultSet =
connection.getMetaData().getIndexInfo(connection.getCatalog(),
connection.getSchema(), table, false, false)) {
while (resultSet.next()) {
String indexName = resultSet.getString(INDEX_NAME);
if (null != indexName) {
result.add(new IndexMetaData(indexName));
}
}
} catch (final SQLException ex) {
if (ORACLE_VIEW_NOT_APPROPRIATE_VENDOR_CODE != ex.getErrorCode()) {
throw ex;
}
}
return result;
}
TableMetaData
Cette classe est l’élément de base de ShardingSphereMetaData
et a la structure suivante :
public final class TableMetaData {
// Table Name
private final String name;
// Column Metadata
private final Map<String, ColumnMetaData> columns;
// Index Metadata
private final Map<String, IndexMetaData> indexes;
//Omit Method
}
De la structure ci-dessus, nous pouvons voir que TableMetaData
est assemblé à partir de ColumnMetaData
et IndexMetaData
, donc le processus de chargement de TableMetaData
peut être comprise comme une couche intermédiaire, et la mise en œuvre spécifique dépend toujours de ColumnMetaDataLoader
et IndexMetaDataLoader
pour obtenir le nom de la table et les liens associés pour le chargement des données.
Donc le relativement simple TableMetaData
processus de chargement est principalement dans le org.apache.shardingsphere.infra.metadata.schema.builder.loader.TableMetaDataLoader#load
méthode, et son processus de chargement de base est le suivant :
public static Optional<TableMetaData> load(final DataSource dataSource, final
String tableNamePattern, final DatabaseType databaseType) throws SQLException {
// Get the Link try (MetaDataLoaderConnectionAdapter connectionAdapter = new
MetaDataLoaderConnectionAdapter(databaseType, dataSource.getConnection())) {
// Format fuzzy matching field of the table name, according to database
type
String formattedTableNamePattern =
databaseType.formatTableNamePattern(tableNamePattern);
// LoadColumnMetaData and IndexMetaData to assemble TableMetaData
return isTableExist(connectionAdapter, formattedTableNamePattern)
? Optional.of(new TableMetaData(tableNamePattern,
ColumnMetaDataLoader.load(
connectionAdapter, formattedTableNamePattern,
databaseType), IndexMetaDataLoader.load(connectionAdapter,
formattedTableNamePattern)))
: Optional.empty();
}
}
SchemaMetaData
D’après l’analyse des deux couches inférieures, il est clair que cette couche est la couche la plus externe d’exposition des métadonnées, et la couche la plus externe est structurée comme un ShardingSphereSchema
avec la structure principale suivante :
/**
* ShardingSphere schema.
*/
@Getter
public final class ShardingSphereSchema {
private final Map<String, TableMetaData> tables;
@SuppressWarnings("CollectionWithoutInitialCapacity")
public ShardingSphereSchema() {
tables = new ConcurrentHashMap<>();
}
public ShardingSphereSchema(final Map<String, TableMetaData> tables) {
this.tables = new ConcurrentHashMap<>(tables.size(), 1);
tables.forEach((key, value) -> this.tables.put(key.toLowerCase(), value));
}
Conformément au concept de schéma, il contient plusieurs tables. L’attribut de ShardingSphereSchema
est une structure de carte, la clé est tableName
, et la valeur est la métadonnée de la table correspondant au tableName
.
L’initialisation se fait principalement via le constructeur. Encore une fois, l’accent est mis sur le chargement des métadonnées de la table, suivons à partir de l’entrée.
Le point d’entrée principal pour l’ensemble de la charge de métadonnées est dans org.apache.shardingsphere.infra.context.metadata.MetaDataContextsBuilder#build
. Dans le build, nous assemblons et chargeons les métadonnées correspondantes via des règles de configuration. Le code de base est le suivant :
/**
* Build meta data contexts.
*
* @exception SQLException SQL exception
* @return meta data contexts
*/
public StandardMetaDataContexts build() throws SQLException {
Map<String, ShardingSphereMetaData> metaDataMap = new HashMap<>
(schemaRuleConfigs.size(), 1);
Map<String, ShardingSphereMetaData> actualMetaDataMap = new HashMap<>
(schemaRuleConfigs.size(), 1);
for (String each : schemaRuleConfigs.keySet()) {
Map<String, DataSource> dataSourceMap = dataSources.get(each);
Collection<RuleConfiguration> ruleConfigs = schemaRuleConfigs.get(each);
DatabaseType databaseType =
DatabaseTypeRecognizer.getDatabaseType(dataSourceMap.values());
// Obtain configuration rules
Collection<ShardingSphereRule> rules =
ShardingSphereRulesBuilder.buildSchemaRules(each, ruleConfigs, databaseType,
dataSourceMap);
// Load actualTableMetaData and logicTableMetaData
Map<TableMetaData, TableMetaData> tableMetaDatas = SchemaBuilder.build(new
SchemaBuilderMaterials(databaseType, dataSourceMap, rules, props));
// Assemble rule metadata
ShardingSphereRuleMetaData ruleMetaData = new
ShardingSphereRuleMetaData(ruleConfigs, rules);
// Assemble data source metadata
ShardingSphereResource resource = buildResource(databaseType, dataSourceMap);
// Assemble database metadata
ShardingSphereSchema actualSchema = new
ShardingSphereSchema(tableMetaDatas.keySet().stream().filter(Objects::nonNull).collect(Collectors.toMap(TableMetaData::getName,
v -> v)));
actualMetaDataMap.put(each, new ShardingSphereMetaData(each, resource,
ruleMetaData, actualSchema));
metaDataMap.put(each, new ShardingSphereMetaData(each, resource,
ruleMetaData, buildSchema(tableMetaDatas)));
}
//
OptimizeContextFactory optimizeContextFactory = new OptimizeContextFactory(actualMetaDataMap);
return new StandardMetaDataContexts(metaDataMap, buildGlobalSchemaMetaData(metaDataMap), executorEngine, props,
optimizeContextFactory);
}
Le code ci-dessus montre que dans la méthode de construction, les données de base de base de données telles que le type de base de données, le pool de connexions de base de données, etc., sont chargées en fonction de la règle de schéma configurée, à travers laquelle l’assemblage du ShardingSphereResource
est terminé ; les…