I. Giới thiệu
Trong bài viết này mình sẽ hướng dẫn config project Spring boot connect multiple database sử dụng hibernate, cụ thể ở đây mình có 2 database là PostgreSQL và MySQL.
Ở đây mình mình sẽ sử dụng kotlin.
II. Implement:
1. Maven dependencies:
Thực hiện import các dependencies cần thiết vào 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> |
Tiếp theo để sử dụng cả Porstgresql và 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 trong file application.properties, ở đây mình connect đến 2 database là MySQL và 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
Bây giờ là bước config data source trong Spring, ở đây mình define 2 package repository và 2 package entity tương ứng với MySQL và PostgreSQL để jpa repository trỏ vào
Mysql:
Tạo 1 file config cho MySQL MySQLConfig.kt
, ở đây mình sẽ custom lại entityManagerFactoryRef
và 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:
Tương tự config cho postgresql, tạo file PostgresqlConfig.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 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
Trong trường hợp muốn config khi load entity xong thì hibernate tự động run script sql thì config thêm phần Initializer như bên dưới:
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
Ví dụ ở đây mình có 1 table users_mysql
trong database mysql
, và mình muốn load toàn bộ dữ liệu ở mysql
sang table user_postgresql
trong database postgresql
Như config ở trên, giờ mình tạo entity cho mysql (package com.example.multidatabase.entity.mysql
) và 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, đã có entity, giờ mình sẽ tạo repository tương ứng 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, bây giờ define 1 component để cứ 30s 1 lần insert user vào MySQL và PostgreSQL:
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 cho phần start spring boot thành công :
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 save user vào 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"}}} |
Cùng check kết quả ở database nào:
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:
Như vậy, việc connect tới nhiều database bằng Spring boot và hibernate có vẻ khá đơn giản phải ko.