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]));

浙公网安备 33010602011771号