I. Introduction
In this article I will guide config project Spring boot connect multiple databases using hibernate, specifically here I have 2 databases: PostgreSQL and MySQL.
Here I will use kotlin.
II. Implement:
1. Maven dependencies:
Import the necessary dependencies into the project:
1 2 3 4 5 6 7 8 9 10 11 12 13 | <dependency> <groupId>com.fasterxml.jackson.module</groupId> <artifactId>jackson-module-kotlin</artifactId> </dependency> <dependency> <groupId>org.jetbrains.kotlin</groupId> <artifactId>kotlin-reflect</artifactId> </dependency> <dependency> <groupId>org.jetbrains.kotlin</groupId> <artifactId>kotlin-stdlib-jdk8</artifactId> </dependency> |
Next to use both Porstgresql and MySQL:
1 2 3 4 5 6 7 8 9 10 11 | <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <scope>runtime</scope> </dependency> <dependency> <groupId>org.postgresql</groupId> <artifactId>postgresql</artifactId> <scope>runtime</scope> </dependency> |
2. Config Propertiese:
Config in file application.properties, here I connect to 2 databases, MySQL and PostgreSQL
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 | spring: mysql-datasource: driver-class-name: com.mysql.jdbc.Driver url: jdbc:mysql://${mysql.host}:${mysql.port}/${mysql.name}?useUnicode=yes&characterEncoding=UTF-8&allowPublicKeyRetrieval=true&useSSL=false username: ${mysql.user} password: ${mysql.password} hibernate.dialect: org.hibernate.dialect.MySQLDialect postgresql-datasource: driver-class-name: org.postgresql.Driver url: jdbc:postgresql://${postgresql.host}:${postgresql.port}/${postgresql.name} username: ${postgresql.user} password: ${postgresql.password} hibernate.dialect: org.hibernate.dialect.PostgreSQLDialect initialization-mode: always jpa: database-platform: default hibernate.ddl-auto: none properties: hibernate: format_sql: true temp.use_jdbc_metadata_defaults: false show-sql: true |
3. Config data source
Now is the config data source step in Spring, here I define 2 package repository and 2 package entities corresponding to MySQL and PostgreSQL so that jpa repository points to
Mysql:
Create a config file for MySQL MySQLConfig.kt
, here I will entityManagerFactoryRef
and transactionManagerRef
:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 | @Configuration @EnableTransactionManagement @EnableJpaRepositories( basePackages = ["com.example.multidatabase.repository.mysql"], entityManagerFactoryRef = "mysqlEntityManagerFactory", transactionManagerRef = "mysqlTransactionManager" ) class MySQLConfig { @Autowired private lateinit var env: Environment @Bean @Primary @ConfigurationProperties(prefix = "spring.datasource") fun mysqlDataSourceProperties(): DataSourceProperties { return DataSourceProperties() } @Bean fun mysqlDataSource(): DataSource { val securityDataSourceProperties = mysqlDataSourceProperties() return DataSourceBuilder.create() .driverClassName(securityDataSourceProperties.driverClassName) .url(securityDataSourceProperties.url) .username(securityDataSourceProperties.username) .password(securityDataSourceProperties.password) .build() } @Bean fun mysqlTransactionManager(): PlatformTransactionManager { val factory: EntityManagerFactory? = mysqlEntityManagerFactory().getObject() return JpaTransactionManager(factory!!) } @Bean(name = ["mysqlEntityManagerFactory"]) @Primary fun mysqlEntityManagerFactory(): LocalContainerEntityManagerFactoryBean { val em = LocalContainerEntityManagerFactoryBean() em.dataSource = mysqlDataSource() em.setPackagesToScan("com.example.multidatabase.entity.mysql") val vendorAdapter = HibernateJpaVendorAdapter() em.jpaVendorAdapter = vendorAdapter val properties = HashMap<String, Any?>() properties["hibernate.hbm2ddl.auto"] = env.getProperty("hibernate.hbm2ddl.auto") properties["hibernate.dialect"] = env.getProperty("spring.datasource.hibernate.dialect") em.setJpaPropertyMap(properties) return em } } |
Postgresql:
Similar config for postgresql, create PostgresqlConfig.kt file:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 | @Configuration @EnableTransactionManagement @EnableJpaRepositories( basePackages = ["com.example.multidatabase.repository.postgresql"], entityManagerFactoryRef = "postgresqlEntityManagerFactory", transactionManagerRef = "postgresqlTransactionManager" ) class PostgresqlConfig { @Autowired private lateinit var env: Environment @Bean @ConfigurationProperties(prefix = "spring.postgresql-datasource") fun postgresqlDataSourceProperties(): DataSourceProperties { return DataSourceProperties() } @Bean fun postgresqlDataSource(): DataSource { val securityDataSourceProperties = postgresqlDataSourceProperties() return DataSourceBuilder.create() .driverClassName(securityDataSourceProperties.driverClassName) .url(securityDataSourceProperties.url) .username(securityDataSourceProperties.username) .password(securityDataSourceProperties.password) .build() } @Bean fun postgresqlTransactionManager(): PlatformTransactionManager { val factory: EntityManagerFactory? = postgresqlEntityManagerFactory().getObject() return JpaTransactionManager(factory!!) } @Bean(name = ["postgresqlEntityManagerFactory"]) @Primary fun postgresqlEntityManagerFactory(): LocalContainerEntityManagerFactoryBean { val em = LocalContainerEntityManagerFactoryBean() em.dataSource = postgresqlDataSource() em.setPackagesToScan("com.example.multidatabase.entity.postgresql") val vendorAdapter = HibernateJpaVendorAdapter() em.jpaVendorAdapter = vendorAdapter val properties = HashMap<String, Any?>() properties["hibernate.hbm2ddl.auto"] = env.getProperty("hibernate.hbm2ddl.auto") properties["hibernate.dialect"] = env.getProperty("spring.second-datasource.hibernate.dialect") em.setJpaPropertyMap(properties) return em } } |
Initializer
In case you want to config when the entity has finished loading, then hibernate automatically runs sql script then config adds the Initializer as shown below:
1 2 3 4 5 6 7 8 9 10 | @Bean fun mysqlDataSourceInitializer(): DataSourceInitializer? { val dataSourceInitializer = DataSourceInitializer() dataSourceInitializer.setDataSource(mysqlDataSource()) val databasePopulator = ResourceDatabasePopulator() databasePopulator.addScript(ClassPathResource("script-mysql.sql")) dataSourceInitializer.setDatabasePopulator(databasePopulator) return dataSourceInitializer } |
1 2 3 4 5 6 7 8 9 10 | @Bean fun postgresqlDataSourceInitializer(): DataSourceInitializer? { val dataSourceInitializer = DataSourceInitializer() dataSourceInitializer.setDataSource(postgresqlDataSource()) val databasePopulator = ResourceDatabasePopulator() databasePopulator.addScript(ClassPathResource("script-postgresql.sql")) dataSourceInitializer.setDatabasePopulator(databasePopulator) return dataSourceInitializer } |
4. Create entity package
For example, here I have 1 users_mysql
table in mysql
database, and I want to load all data in mysql
to user_postgresql
table in postgresql
database
As above config, now I create the entity for mysql (package com.example.multidatabase.entity.mysql
) and postgresql (package com.example.multidatabase.entity.postgresql
):
1 2 3 4 5 6 | -com.example.multidatabase.entity --mysql ---UsersMySQLEntity.kt --postgresql ---UsersPostgreSQLEntity.kt |
UsersMySQLEntity.kt:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 | @Entity @Table(name = "user_email") class UsersMySQLEntity { @Id @Column(name = "user_id", unique = true) var userId: String? = null @Column(name = "email_address", nullable = false, unique = true) var emailAddress: String? = null @Column(name = "password", nullable = false) var userPassword: String? = null @Column(name = "reset_password_token", nullable = true) var resetPasswordToken: String? = null @Column(name = "reset_password_sent_at", nullable = true) var resetPasswordSentAt: LocalDateTime? = null @Column(name = "last_try_count", nullable = true) var lastTryCount: Int? = null @Column(name = "last_try_date", nullable = true) var lastTryDate: LocalDateTime? = null @Column(name = "created_at", nullable = false) var createdDate: LocalDateTime? = null @Column(name = "deleted_at", nullable = true) var deletedAt: LocalDateTime? = null @Column(name = "updated_at", nullable = false) var updatedDate: LocalDateTime? = null } |
PostgreSQLEntity.kt:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 | @Entity @Table(name = "users") class PostgreSQLEntity { @Id @Column(name = "id", nullable = false) var id: Int? = null @Column(name = "provider", nullable = true) var provider: String? = null @Column(name = "uid", nullable = true) var uid: String? = null @Column(name = "email", nullable = true) var email: String? = null @Column(name = "encrypted_password", nullable = true) var encryptedPassword: String? = null @Column(name = "reset_password_token", nullable = true) var resetPasswordToken: String? = null @Column(name = "reset_password_sent_at", nullable = true) var resetPasswordSentAt: LocalDateTime? = null @Column(name = "name", nullable = true) var name: String? = null @Column(name = "created_at", nullable = false) var createdDate: LocalDateTime? = null @Column(name = "deleted_at", nullable = true) var deletedAt: LocalDateTime? = null @Column(name = "updated_at", nullable = false) var updatedDate: LocalDateTime? = null } |
5. Create repository package:
OK, had an entity, now I will create the corresponding repository mysql (package com.example.multidatabase.repository.mysql
), postgresql (package com.example.multidatabase.repository.postgresql
):
1 2 3 4 5 6 | -com.example.multidatabase.repository --mysql ---UsersMySQLRepository.kt --postgresql ---UsersPostgreSQLRepository.kt |
UsersMySQLRepository.kt:
1 2 3 | interface UsersMySQLRepository : JpaRepository<UsersMySQLEntity, String> { } |
UsersPostgreSQLRepository.kt:
1 2 3 | interface UsersPostgreSQLRepository : JpaRepository<UsersPostgreSQLEntity, String> { } |
6. Execute:
OK, now define 1 component to insert the user into MySQL and PostgreSQL every 30 seconds:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 | @Component class MigrationComponent( val usersMySQLRepository: UsersMySQLRepository, val usersPostgreSQLRepository: UsersPostgreSQLRepository) { companion object { val LOG = LoggerFactory.getLogger(MigrationComponent::class.java) } @Scheduled(cron = "*/30 * * ? * *") fun process() { val userMysql = createNewUserMySQL() usersMySQLRepository.saveAndFlush(userMysql) LOG.info("User MySQL:") LOG.info(ObjectMapper().writeValueAsString(userMysql)) val userPostgreSQL = ModelMapper().map(userMysql, UsersPostgreSQLEntity::class.java) usersPostgreSQLRepository.saveAndFlush(userPostgreSQL) LOG.info("User PostgreSQL") LOG.info(ObjectMapper().writeValueAsString(userPostgreSQL)) } private fun createNewUserMySQL(): UsersMySQLEntity { val user = UsersMySQLEntity() user.emailAddress = String.format("test+% <a class="__cf_email__" href="/cdn-cgi/l/email-protection">[email protected]</a> ", LocalDateTime.now().toLocalTime().toString()) return user } } |
7. Result:
Log for successful start spring boot:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 | . ____ _ __ _ _ /\ / ___'_ __ _ _(_)_ __ __ _ ( ( )___ | '_ | '_| | '_ / _` | \/ ___)| |_)| | | | | || (_| | ) ) ) ) ' |____| .__|_| |_|_| |___, | / / / / =========|_|==============|___/=/_/_/_/ :: Spring Boot :: (v2.3.1.RELEASE) 2020-06-21 10:49:27,699 INFO [main] o.s.b.StartupInfoLogger:55: Starting MultidatabaseApplicationKt on hoang-MS-7B84 with PID 16023 (/home/hoang/Dev/HOME_WORK/multidatabase/target/classes started by hoang in /home/hoang/Dev/HOME_WORK/multidatabase) 2020-06-21 10:49:27,701 INFO [main] o.s.b.SpringApplication:655: The following profiles are active: dev 2020-06-21 10:49:28,287 INFO [main] o.s.d.r.c.RepositoryConfigurationDelegate:127: Bootstrapping Spring Data JPA repositories in DEFAULT mode. 2020-06-21 10:49:28,330 INFO [main] o.s.d.r.c.RepositoryConfigurationDelegate:187: Finished Spring Data repository scanning in 34ms. Found 1 JPA repository interfaces. 2020-06-21 10:49:28,331 INFO [main] o.s.d.r.c.RepositoryConfigurationDelegate:127: Bootstrapping Spring Data JPA repositories in DEFAULT mode. 2020-06-21 10:49:28,336 INFO [main] o.s.d.r.c.RepositoryConfigurationDelegate:187: Finished Spring Data repository scanning in 4ms. Found 1 JPA repository interfaces. 2020-06-21 10:49:28,982 INFO [main] o.s.b.w.e.t.TomcatWebServer:108: Tomcat initialized with port(s): 8080 (http) 2020-06-21 10:49:28,988 INFO [main] o.a.j.l.DirectJDKLog:173: Initializing ProtocolHandler ["http-nio-8080"] 2020-06-21 10:49:28,989 INFO [main] o.a.j.l.DirectJDKLog:173: Starting service [Tomcat] 2020-06-21 10:49:28,990 INFO [main] o.a.j.l.DirectJDKLog:173: Starting Servlet engine: [Apache Tomcat/9.0.36] 2020-06-21 10:49:29,041 INFO [main] o.a.j.l.DirectJDKLog:173: Initializing Spring embedded WebApplicationContext 2020-06-21 10:49:29,041 INFO [main] o.s.b.w.s.c.ServletWebServerApplicationContext:285: Root WebApplicationContext: initialization completed in 1294 ms Loading class `com.mysql.jdbc.Driver'. This is deprecated. The new driver class is `com.mysql.cj.jdbc.Driver'. The driver is automatically registered via the SPI and manual loading of the driver class is generally unnecessary. 2020-06-21 10:49:29,350 INFO [main] c.z.h.HikariDataSource:110: HikariPool-1 - Starting... 2020-06-21 10:49:29,351 WARN [main] c.z.h.u.DriverDataSource:70: Registered driver with driverClassName=com.mysql.jdbc.Driver was not found, trying direct instantiation. 2020-06-21 10:49:29,431 INFO [main] c.z.h.HikariDataSource:123: HikariPool-1 - Start completed. 2020-06-21 10:49:29,659 INFO [main] o.s.o.j.AbstractEntityManagerFactoryBean:416: Initialized JPA EntityManagerFactory for persistence unit 'default' 2020-06-21 10:49:29,693 INFO [main] c.z.h.HikariDataSource:110: HikariPool-2 - Starting... 2020-06-21 10:49:29,734 INFO [main] c.z.h.HikariDataSource:123: HikariPool-2 - Start completed. 2020-06-21 10:49:29,780 INFO [main] o.s.o.j.AbstractEntityManagerFactoryBean:416: Initialized JPA EntityManagerFactory for persistence unit 'default' 2020-06-21 10:49:30,101 INFO [main] o.s.s.c.ExecutorConfigurationSupport:181: Initializing ExecutorService 'applicationTaskExecutor' 2020-06-21 10:49:30,208 INFO [main] o.s.s.c.ExecutorConfigurationSupport:181: Initializing ExecutorService 'taskScheduler' 2020-06-21 10:49:30,226 INFO [main] o.a.j.l.DirectJDKLog:173: Starting ProtocolHandler ["http-nio-8080"] 2020-06-21 10:49:30,236 INFO [main] o.s.b.w.e.t.TomcatWebServer:220: Tomcat started on port(s): 8080 (http) with context path '' 2020-06-21 10:49:30,246 INFO [main] o.s.b.StartupInfoLogger:61: Started MultidatabaseApplicationKt in 2.975 seconds (JVM running for 3.382) |
Log user to database:
1 2 3 4 5 6 7 8 9 10 11 12 13 | User MySQL: 2020-06-21 11:02:00,081 INFO [scheduling-1] c.e.m.c.MigrationComponent:27: {"userId":"eb77366f-0ef1-43b8-90e1-1a698c3e51da","emailAddress":"test+11: <a class="__cf_email__" href="/cdn-cgi/l/email-protection">[email protected]</a> ","userPassword":"Bcrypt","resetPasswordToken":null,"resetPasswordSentAt":null,"lastTryCount":null,"lastTryDate":null,"createdDate":{"dayOfWeek":"SUNDAY","dayOfYear":173,"year":2020,"month":"JUNE","nano":0,"monthValue":6,"dayOfMonth":21,"hour":11,"minute":2,"second":0,"chronology":{"calendarType":"iso8601","id":"ISO"}},"deletedAt":null,"updatedDate":{"dayOfWeek":"SUNDAY","dayOfYear":173,"year":2020,"month":"JUNE","nano":0,"monthValue":6,"dayOfMonth":21,"hour":11,"minute":2,"second":0,"chronology":{"calendarType":"iso8601","id":"ISO"}}} 2020-06-21 11:02:00,161 INFO [scheduling-1] c.e.m.c.MigrationComponent:30: User PostgreSQL 2020-06-21 11:02:00,164 INFO [scheduling-1] c.e.m.c.MigrationComponent:31: {"userId":"eb77366f-0ef1-43b8-90e1-1a698c3e51da","provider":"email","uid":null,"email":"test+11: <a class="__cf_email__" href="/cdn-cgi/l/email-protection">[email protected]</a> ","userPassword":"Bcrypt","resetPasswordToken":null,"resetPasswordSentAt":null,"createdDate":{"dayOfWeek":"SUNDAY","dayOfYear":173,"year":2020,"month":"JUNE","nano":0,"monthValue":6,"dayOfMonth":21,"hour":11,"minute":2,"second":0,"chronology":{"calendarType":"iso8601","id":"ISO"}},"deletedAt":null,"updatedDate":{"dayOfWeek":"SUNDAY","dayOfYear":173,"year":2020,"month":"JUNE","nano":0,"monthValue":6,"dayOfMonth":21,"hour":11,"minute":2,"second":0,"chronology":{"calendarType":"iso8601","id":"ISO"}}} 2020-06-21 11:02:30,005 INFO [scheduling-1] c.e.m.c.MigrationComponent:26: User MySQL: 2020-06-21 11:02:30,008 INFO [scheduling-1] c.e.m.c.MigrationComponent:27: {"userId":"9583b283-26e7-4640-8cb8-8f304b0a5494","emailAddress":"test+11:02: <a class="__cf_email__" href="/cdn-cgi/l/email-protection">[email protected]</a> ","userPassword":"Bcrypt","resetPasswordToken":null,"resetPasswordSentAt":null,"lastTryCount":null,"lastTryDate":null,"createdDate":{"dayOfWeek":"SUNDAY","dayOfYear":173,"year":2020,"month":"JUNE","nano":0,"monthValue":6,"dayOfMonth":21,"hour":11,"minute":2,"second":30,"chronology":{"calendarType":"iso8601","id":"ISO"}},"deletedAt":null,"updatedDate":{"dayOfWeek":"SUNDAY","dayOfYear":173,"year":2020,"month":"JUNE","nano":0,"monthValue":6,"dayOfMonth":21,"hour":11,"minute":2,"second":30,"chronology":{"calendarType":"iso8601","id":"ISO"}}} 2020-06-21 11:02:30,017 INFO [scheduling-1] c.e.m.c.MigrationComponent:30: User PostgreSQL 2020-06-21 11:02:30,020 INFO [scheduling-1] c.e.m.c.MigrationComponent:31: {"userId":"9583b283-26e7-4640-8cb8-8f304b0a5494","provider":"email","uid":null,"email":"test+11:02: <a class="__cf_email__" href="/cdn-cgi/l/email-protection">[email protected]</a> ","userPassword":"Bcrypt","resetPasswordToken":null,"resetPasswordSentAt":null,"createdDate":{"dayOfWeek":"SUNDAY","dayOfYear":173,"year":2020,"month":"JUNE","nano":0,"monthValue":6,"dayOfMonth":21,"hour":11,"minute":2,"second":30,"chronology":{"calendarType":"iso8601","id":"ISO"}},"deletedAt":null,"updatedDate":{"dayOfWeek":"SUNDAY","dayOfYear":173,"year":2020,"month":"JUNE","nano":0,"monthValue":6,"dayOfMonth":21,"hour":11,"minute":2,"second":30,"chronology":{"calendarType":"iso8601","id":"ISO"}}} 2020-06-21 11:03:00,006 INFO [scheduling-1] c.e.m.c.MigrationComponent:26: User MySQL: 2020-06-21 11:03:00,009 INFO [scheduling-1] c.e.m.c.MigrationComponent:27: {"userId":"3df06730-9388-4ea1-a3c5-8e370be01a48","emailAddress":"test+11: <a class="__cf_email__" href="/cdn-cgi/l/email-protection">[email protected]</a> ","userPassword":"Bcrypt","resetPasswordToken":null,"resetPasswordSentAt":null,"lastTryCount":null,"lastTryDate":null,"createdDate":{"dayOfWeek":"SUNDAY","dayOfYear":173,"year":2020,"month":"JUNE","nano":0,"monthValue":6,"dayOfMonth":21,"hour":11,"minute":3,"second":0,"chronology":{"calendarType":"iso8601","id":"ISO"}},"deletedAt":null,"updatedDate":{"dayOfWeek":"SUNDAY","dayOfYear":173,"year":2020,"month":"JUNE","nano":0,"monthValue":6,"dayOfMonth":21,"hour":11,"minute":3,"second":0,"chronology":{"calendarType":"iso8601","id":"ISO"}}} 2020-06-21 11:03:00,017 INFO [scheduling-1] c.e.m.c.MigrationComponent:30: User PostgreSQL 2020-06-21 11:03:00,020 INFO [scheduling-1] c.e.m.c.MigrationComponent:31: {"userId":"3df06730-9388-4ea1-a3c5-8e370be01a48","provider":"email","uid":null,"email":"test+11: <a class="__cf_email__" href="/cdn-cgi/l/email-protection">[email protected]</a> ","userPassword":"Bcrypt","resetPasswordToken":null,"resetPasswordSentAt":null,"createdDate":{"dayOfWeek":"SUNDAY","dayOfYear":173,"year":2020,"month":"JUNE","nano":0,"monthValue":6,"dayOfMonth":21,"hour":11,"minute":3,"second":0,"chronology":{"calendarType":"iso8601","id":"ISO"}},"deletedAt":null,"updatedDate":{"dayOfWeek":"SUNDAY","dayOfYear":173,"year":2020,"month":"JUNE","nano":0,"monthValue":6,"dayOfMonth":21,"hour":11,"minute":3,"second":0,"chronology":{"calendarType":"iso8601","id":"ISO"}}} |
Let’s check the database results:
Table users_postgresql
:
1 2 3 4 5 6 7 8 | |id|provider|uid|email|encrypted_password|created_by|updated_by|reset_password_token|reset_password_sent_at|created_at|updated_at|deleted_at|line_id| |--|--------|---|-----|------------------|----------|----------|--------------------|----------------------|----------|----------|----------|-------| |eb77366f-0ef1-43b8-90e1-1a698c3e51da|email||test+11: <a class="__cf_email__" href="/cdn-cgi/l/email-protection">[email protected]</a> |Bcrypt|||||2020-06-21 11:02:00|2020-06-21 11:02:00||| |9583b283-26e7-4640-8cb8-8f304b0a5494|email||test+11:02: <a class="__cf_email__" href="/cdn-cgi/l/email-protection">[email protected]</a> |Bcrypt|||||2020-06-21 11:02:30|2020-06-21 11:02:30||| |3df06730-9388-4ea1-a3c5-8e370be01a48|email||test+11: <a class="__cf_email__" href="/cdn-cgi/l/email-protection">[email protected]</a> |Bcrypt|||||2020-06-21 11:03:00|2020-06-21 11:03:00||| |a042d902-aa46-4117-afea-a7cabd3daacb|email||test+11:03: <a class="__cf_email__" href="/cdn-cgi/l/email-protection">[email protected]</a> |Bcrypt|||||2020-06-21 11:03:30|2020-06-21 11:03:30||| |
Table users_mysql
:
1 2 3 4 5 6 7 | |user_id|email_address|password|reset_password_token|reset_password_sent_at|last_try_count|last_try_date|created_at|deleted_at|updated_at| |-------|-------------|--------|--------------------|----------------------|--------------|-------------|----------|----------|----------| |eb77366f-0ef1-43b8-90e1-1a698c3e51da|test+11: <a class="__cf_email__" href="/cdn-cgi/l/email-protection">[email protected]</a> |Bcrypt|||||2020-06-21 04:02:00.0||2020-06-21 04:02:00.0| |9583b283-26e7-4640-8cb8-8f304b0a5494|test+11:02: <a class="__cf_email__" href="/cdn-cgi/l/email-protection">[email protected]</a> |Bcrypt|||||2020-06-21 04:02:30.0||2020-06-21 04:02:30.0| |3df06730-9388-4ea1-a3c5-8e370be01a48|test+11: <a class="__cf_email__" href="/cdn-cgi/l/email-protection">[email protected]</a> |Bcrypt|||||2020-06-21 04:03:00.0||2020-06-21 04:03:00.0| |a042d902-aa46-4117-afea-a7cabd3daacb|test+11:03: <a class="__cf_email__" href="/cdn-cgi/l/email-protection">[email protected]</a> |Bcrypt|||||2020-06-21 04:03:30.0||2020-06-21 04:03:30.0| |
III. Sumary:
Thus, connecting to multiple databases with Spring boot and hibernate seems quite simple right.