代码之家  ›  专栏  ›  技术社区  ›  Daniel Taub

使用hibernate以编程方式验证架构

  •  1
  • Daniel Taub  · 技术社区  · 7 年前

    在mose项目中,如何运行 java app

    spring.jpa.hibernate.ddl-auto=validate
    

    我遇到了一个问题,我需要在运行期间的特定时间验证我的模式,有什么方法可以实现吗?

    我看到hibernate用 AbstractSchemaValidator 我正在使用spring和hibernate,但我没有找到任何关于如何处理它的信息,
    我唯一发现的是 How to validate database schema programmatically in hibernate with annotations? ,但它已在的旧版本中删除 spring-boot

    <dependency>
        <groupId>org.springframework.data</groupId>
        <artifactId>spring-data-jpa</artifactId>
        <version>2.0.4.RELEASE</version>
    </dependency>
    

    2 回复  |  直到 7 年前
        1
  •  4
  •   Oleksii Zghurskyi    7 年前

    这是一个解决方案,如果您的用例需要:

    • 颗粒状&显式控制架构的哪一部分应为
    • 需要验证多个模式
    • 需要验证服务未使用的模式,定时验证器正在该服务上运行
    • 应用程序使用的db连接不应以任何方式受到验证的影响(也就是说,您不想从主连接池借用连接)

    如何执行计划架构验证的示例 :

    @SpringBootApplication
    @EnableScheduling
    @EnableConfigurationProperties(ScheamValidatorProperties.class)
    public class SchemaValidatorApplication {
         public static void main(String[] args) {
           SpringApplication.run(SchemaValidatorApplication.class, args);
        }
    }
    
    @ConfigurationProperties("schema-validator")
    class ScheamValidatorProperties {
        public Map<String, String> settings = new HashMap<>();
    
        public ScheamValidatorProperties() {
        }
    
        public Map<String, String> getSettings() { 
            return this.settings;
        }
    
        public void setSome(Map<String, String> settings) { 
            this.settings = settings;
        }
    }
    
    @Component
    class ScheduledSchemaValidator {
    
        private ScheamValidatorProperties props;
    
        public ScheduledSchemaValidator(ScheamValidatorProperties props) {
            this.props = props;
        }
    
        @Scheduled(cron = "0 0/1 * * * ?")
        public void validateSchema() {
            StandardServiceRegistry serviceRegistry = new StandardServiceRegistryBuilder()
                .applySettings(props.getSettings())
                .build();
    
            Metadata metadata = new MetadataSources(serviceRegistry)
                .addAnnotatedClass(Entity1.class)
                .addAnnotatedClass(Entity2.class)
                .buildMetadata();
    
            try {
                new SchemaValidator().validate(metadata, serviceRegistry);
            } catch (Exception e) {
                System.out.println("Validation failed: " + e.getMessage());
            } finally {
                StandardServiceRegistryBuilder.destroy(serviceRegistry);
            }
        }
    }
    
    @Entity
    @Table(name = "table1")
    class Entity1 {
        @Id
        @GeneratedValue(strategy = GenerationType.IDENTITY)
        private Long id;
    
        Entity1() {}
    
        public Long getId() {
            return id;
        }
    
    }
    
    @Entity
    @Table(name = "table2")
    class Entity2 {
        @Id
        @GeneratedValue(strategy = GenerationType.IDENTITY)
        private Long id;
    
        Entity2() {}
    
        public Long getId() {
            return id;
        }
    }
    
    CREATE DATABASE IF NOT EXISTS testdb;
    
    CREATE TABLE IF NOT EXISTS `table1` (
      `id` bigint(20) NOT NULL AUTO_INCREMENT,
      PRIMARY KEY (`id`)
    );
    
    CREATE TABLE IF NOT EXISTS `table2` (
      `id` bigint(20) NOT NULL AUTO_INCREMENT,
      PRIMARY KEY (`id`)
    );
    
    
    1. application.yml
    spring:
      cache:
        type: none
      datasource:
        driver-class-name: com.mysql.cj.jdbc.Driver
        url: jdbc:mysql://localhost:3309/testdb?useSSL=false&nullNamePatternMatchesAll=true&serverTimezone=UTC&allowPublicKeyRetrieval=true
        username: test_user
        password: test_password
        testWhileIdle: true
        validationQuery: SELECT 1
      jpa:
        show-sql: false
        database-platform: org.hibernate.dialect.MySQL8Dialect
        hibernate:
          ddl-auto: none
          naming:
            physical-strategy: org.springframework.boot.orm.jpa.hibernate.SpringPhysicalNamingStrategy
            implicit-strategy: org.springframework.boot.orm.jpa.hibernate.SpringImplicitNamingStrategy
        properties:
          hibernate.dialect: org.hibernate.dialect.MySQL8Dialect
          hibernate.cache.use_second_level_cache: false
          hibernate.cache.use_query_cache: false
          hibernate.generate_statistics: false
          hibernate.hbm2ddl.auto: validate
    
    schema-validator:
        settings:
            connection.driver_class: com.mysql.cj.jdbc.Driver
            hibernate.dialect: org.hibernate.dialect.MySQL8Dialect
            hibernate.connection.url: jdbc:mysql://localhost:3309/testdb?autoReconnect=true&useSSL=false&allowPublicKeyRetrieval=true
            hibernate.connection.username: test_user
            hibernate.connection.password: test_password
            hibernate.default_schema: testdb
    
    
    1. docker-compose.yml
    version: '3.0'
    
    services:
      db:
        image: mysql:8.0.14
        restart: always
        ports:
         - 3309:3306
        environment:
          MYSQL_ROOT_PASSWORD: test_password
          MYSQL_DATABASE: testdb
          MYSQL_USER: test_user
          MYSQL_PASSWORD: test_password
    
        2
  •  3
  •   Ken Chan    7 年前

    SchemaValidator 要重用已经在项目中配置的连接配置和映射信息,而不是再次定义它们来进行模式验证,那么您应该考虑我的解决方案,这样您就可以干了,不需要在两个不同的地方维护这些配置。

    图式发生器 Metadata 实例,该实例仅在引导休眠期间可用。但是我们可以使用Hibernate Integrator API(如中所述) here

    SchemaValidateService 它实现了Hibernate Integrator API来捕获 元数据 . 还设置了一个 @Scheduled 方法在所需时间验证架构。

    @Component
    public class SchemaValidateService implements Integrator {
    
        private Metadata metadata;
    
        @Override
        public void integrate(Metadata metadata, SessionFactoryImplementor sessionFactory,
                SessionFactoryServiceRegistry serviceRegistry) {
            this.metadata = metadata;
        }
    
        @Override
        public void disintegrate(SessionFactoryImplementor sessionFactory, SessionFactoryServiceRegistry serviceRegistry) {
        }
    
        //Adjust the scheduled time here
        @Scheduled(cron = "0 0/1 * * * ?")
        public void validate() {
            try {
                System.out.println("Start validating schema");
                new SchemaValidator().validate(metadata);
            } catch (Exception e) {
                //log the validation error here.
            }
            System.out.println("Finish validating schema....");
        }
    }
    

    @SpringBootApplication
    @EnableScheduling
    public class App {
    
        @Bean
        public HibernatePropertiesCustomizer hibernatePropertiesCustomizer(SchemaValidateService schemaValidateService) {
            return (prop -> {
                List<Integrator> integrators = new ArrayList<>();
                integrators.add(schemaValidateService);
                prop.put("hibernate.integrator_provider", (IntegratorProvider) () -> integrators);
            });
        }
    }
    

    此外,此解决方案应该具有更好的性能,因为它不需要每次都创建新的数据库连接来验证模式,因为它可以从现有连接池中获取连接。