JPA hibernate 比对Entity和DB生成DDL

JPA hibernate 比对Entity和DB生成DDL

JPA 获取Entity信息

//build configuration
//若不需要连接db,则configuration内可为空,即不需要设置property
Configuration configuration = new Configuration();
configuration.setProperty(Environment.DIALECT, DIALECT.getName());
configuration.setProperty(Environment.USER, USER_NAME);
configuration.setProperty(Environment.PASS, PASSWORD);
configuration.setProperty(Environment.URL, URL);
configuration.setProperty(Environment.DRIVER, DRIVER);
configuration.setPhysicalNamingStrategy(new SpringPhysicalNamingStrategy());
//build metadata
SessionFactory sessionFactory = config.buildSessionFactory();
StandardServiceRegistryImpl standardServiceRegistry = (StandardServiceRegistryImpl) sessionFactory.getSessionFactoryOptions().getServiceRegistry();
this.serviceRegistry = standardServiceRegistry;
MetadataSources metadataSources = new MetadataSources(standardServiceRegistry, true);
if (StringUtils.isNotEmpty(packagePath)) {
    //扫描包路径下所有的entity
    for (Class klass : findClassesWithEntityAnnotation(packagePath)) {
        metadataSources.addAnnotatedClass(klass);
    }
}
MetadataBuilder builder = metadataSources.getMetadataBuilder();
return (MetadataImpl) builder.applyPhysicalNamingStrategy(new SpringPhysicalNamingStrategy()).build();
//get all TableInfo
for (Namespace namespace : metadata.getDatabase().getNamespaces()) {
    Collection<org.hibernate.mapping.Table> tables = namespace.getTables();
}

tips:可以使用SchemaExport 或SchemaUpdate hbm2ddl工具生成ddl

SchemaExport schema = new SchemaExport();
schema.setOutputFile("schema1.sql");
//上述步骤里的metadata
schema.createOnly(EnumSet.of(TargetType.SCRIPT), metadata);

scanPackage

List<Class> result = new ArrayList<>();
ClassPathScanningCandidateComponentProvider provider = new ClassPathScanningCandidateComponentProvider(false);
provider.addIncludeFilter(new AnnotationTypeFilter(Entity.class));
Set<BeanDefinition> beanDefinitions = provider.findCandidateComponents(packageName);
for (BeanDefinition bd : beanDefinitions) {
    result.add(Class.forName(bd.getBeanClassName()));
}
return result;

获取所有DB table信息

//获取manageTool
HibernateSchemaManagementTool managementTool = (HibernateSchemaManagementTool)serviceRegistry.getService(SchemaManagementTool.class);
final ExceptionHandler exceptionHandler = new ExceptionHandlerCollectingImpl();
Map config = new HashMap(serviceRegistry.getService(ConfigurationService.class).getSettings());
final ExecutionOptions executionOptions = SchemaManagementToolCoordinator.buildExecutionOptions(
    config,
    exceptionHandler
        );
final JdbcContext jdbcContext = managementTool.resolveJdbcContext(executionOptions.getConfigurationValues());
final DdlTransactionIsolator ddlTransactionIsolator = managementTool.getDdlTransactionIsolator(jdbcContext);
//获取dataBaseInfo
final DatabaseInformation databaseInformation = Helper.buildDatabaseInformation(
    managementTool.getServiceRegistry(),
    ddlTransactionIsolator,
    metadata.getDatabase().getDefaultNamespace().getName()
);
//metadata and namespace
Iterable<Namespace> namespaces = metadata.getDatabase().getNamespaces();
//get all columns information
NameSpaceTablesInformation information = databaseInformation.getTablesInformation(namespace);
Collection<Table> tables = namespace.getTables();
for (Table table : tables) {
    if (Objects.isNull(table))continue;
    TableInformation tableInformation = information.getTableInformation(table);
    //column信息
    Map<Identifier, ColumnInformation> columns = (Map<Identifier, ColumnInformation>) ReflectUtil.getFieldValue(tableInformation, "columns");
    if(MapUtil.isEmpty(columns))continue;
}

Compare DB and Entity

由于ColumnInformation和Column对象无直接关联,需要手动按照需求进行比较处理

建议使用Maps.uniqueIndex进行分组,然后使用Maps.difference进行对象比较,从而获取差异

生成DDL

这里使用下述开源框架进行处理

<dependency>
    <groupId>com.github.drinkjava2</groupId>
    <artifactId>jdialects</artifactId>
    <version>5.0.12.jre8</version>  <!-- 或最新版本 -->
</dependency>

tips:按照JPA方言获取框架内的DIALECT

Dialect[] dialects = Dialect.dialects;
List<String> names = Stream.of(dialects).map(Dialect::getName).collect(Collectors.toList());
//jpa 方言取最相似的方言名称
Optional<String> name = names.stream().max(Comparator.comparing(value -> StrUtil.similar(value,JPAConstant.DIALECT.getSimpleName())));
name.ifPresent(s -> SQL_DIALECT = new Dialect(s));

DropColumn

TableModel tableModel = new TableModel(tableName);
for (Map.Entry<String, ColumnInformation> entry : modelContext.getPlusDBColumn().entrySet()) {
      ColumnModel columnModel = new ColumnModel(entry.getKey());
      columnModel.setTableModel(tableModel);
      dropModel.add(columnModel);
  }
String[] ddl = SQL_DIALECT.toDropColumnDDL(dropModel.toArray(new ColumnModel[0]));

CreateColumn

TableModel tableModel = new TableModel(tableName);
//jpa entity比对DB 生成create ddl
for (Map.Entry<String, Column> entry : modelContext.getPlusJpaField().entrySet()) {
    ColumnModel columnModel = new ColumnModel(entry.getKey());
    Type type = TypeUtils.javaType2DialectType(entry.getValue().getValue().getType().getReturnedClass());
    if (Objects.isNull(type)) {
        columnModel = columnModel.CLOB();
    } else {
        columnModel.setColumnType(type);
    }
    if (StringUtils.isNoneEmpty(entry.getValue().getDefaultValue())) {
        columnModel.setDefaultValue(entry.getValue().getDefaultValue());
    }
    columnModel.setTableModel(tableModel);
    CreateModel.add(columnModel);
}
String[] ddl = SQL_DIALECT.toAddColumnDDL(CreateModel.toArray(new ColumnModel[0]));
posted @ 2022-04-08 16:32  WheelCode  阅读(258)  评论(0)    收藏  举报