Проверяйте схему программно, используя Hibernate - PullRequest
0 голосов
/ 31 января 2019

В проектах mose способ запуска java app с проверкой схемы заключается в такой конфигурации (при использовании Spring):

spring.jpa.hibernate.ddl-auto=validate

Я столкнулся с проблемой, которая необходима для проверки моей схемы наопределенное время во время работы, есть ли способ реализовать это?

Я видел, что Hibernate управлял этим с AbstractSchemaValidator, я использую Spring с Hibernate, и я не сделалнашел любую информацию, как с этим справиться,
единственное, что я нашел, это Как программно проверить схему базы данных в спящем режиме с аннотациями?, но он был удален в более старых версиях spring-boot

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

есть идеи?

Ответы [ 2 ]

0 голосов
/ 04 февраля 2019

Если вы хотите позволить SchemaValidator повторно использовать конфигурацию соединения и информацию о сопоставлении, которые уже сконфигурированы в проекте, а не определять их еще раз для проверки схемы, вы должны рассмотреть мое решение таким образом, что вы СУХОЙ и донНе нужно поддерживать эти конфигурации в двух разных местах.

На самом деле, SchemaValidator требует, это экземпляр Metadata, который доступен только во время начальной загрузки Hibernate.Но мы можем использовать Hibernate Integrator API (как описано в здесь ), чтобы захватить его, чтобы мы могли проверить их позже.

(1) Создать SchemaValidateService, который реализует Hibernate Integrator API для захватаMetadata.Также настройте метод @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....");
    }
}

(2) Зарегистрируйте SchemaValidateService в Hibernate

@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);
        });
    }
}

Кроме того, это решение должно иметь лучшую производительностьпоскольку ему не нужно каждый раз создавать новое соединение с базой данных для проверки схемы, поскольку он может просто извлечь соединение из существующего пула соединений.

0 голосов
/ 03 февраля 2019

Это решение, если ваш вариант использования требует:

  • детального и явного контроля над тем, какая часть схемы должна быть проверена
  • необходимо проверить несколько схем
  • необходимо проверить схему, которая не используется службой, на которой запущен запланированный валидатор.
  • Соединения в дБ, используемые приложением, никоим образом не должны зависеть от проверки (т. Е.не хочу заимствовать соединение из основного пула соединений)

Если вышеизложенное относится к вашим потребностям, то это пример того, как выполнить запланированную проверку схемы :

  1. Источники
@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;
    }
}
schema.sql
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`)
);

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

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
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...