使用休眠模式以编程方式验证架构 [英] Validate schema programmatically using hibernate
问题描述
在mose项目中,使用架构验证运行java app
的方式就是使用该配置(使用spring时):
spring.jpa.hibernate.ddl-auto=validate
我遇到了一个问题,我需要在运行过程中的特定时间验证我的架构,有什么方法可以实现?
我看到hibernate使用如何以编程方式在带休眠的休眠模式下验证数据库模式?
,但在spring-boot
<dependency>
<groupId>org.springframework.data</groupId>
<artifactId>spring-data-jpa</artifactId>
<version>2.0.4.RELEASE</version>
</dependency>
有什么想法吗?
这是解决方案,如果您的用例需要:
- 颗粒&明确控制应在架构的哪一部分 已验证
- 需要验证多个模式
- 需要验证运行计划的验证程序的服务未使用的架构
- 应用程序使用的数据库连接不应以任何方式受到验证的影响(这意味着您不想从主连接池中借用连接)
如果以上满足您的需要,那么这是如何执行计划的模式验证的示例:
- 来源
@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
In mose projects the way to run your java app
with schema validation is with that configuration (when using spring):
spring.jpa.hibernate.ddl-auto=validate
I ran into a problem that I need to validate my schema at a specific times during running, is there any way to implement that?
I saw that hibernate managed it with the AbstractSchemaValidator
,
I'm using spring with hibernate, and I didn't found any information how to deal with it,
the only thing I found is How to validate database schema programmatically in hibernate with annotations?
, but it was removed in the older versions of spring-boot
<dependency>
<groupId>org.springframework.data</groupId>
<artifactId>spring-data-jpa</artifactId>
<version>2.0.4.RELEASE</version>
</dependency>
any ideas?
This is solution, if your use case requires:
- granular & explicit control of which part of the schema should be validated
- the need is to validate multiple schemas
- the need is to validate schema that is not used by the service, on which scheduled validator is running
- db connections used by application should not be influenced by validation in any way (meaning, you don't want to borrow connection from main connections pool)
If above applies for your needs, than this is example of how to do scheduled schema validation:
- Sources
@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
这篇关于使用休眠模式以编程方式验证架构的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!