Monday, February 11, 2019

10. Application with multiple datasources

Many times it is a practical requirement to have multiple databases for a single application. These databases could be at different locations on the cloud and different entities in your application may be dealing with these databases.
Multi-tenancy is a great requirement when multiple data sources are needed. Many tenants may insist on having their own databases. Here we present how we can configure the spring application to interact with multiple databases.
The first step is to look at our application.properties file. We have a list of properties defined for the default dataSource which we will need to replicate for our second database. Let's assume we are going to use two data sources, the first one is called the user and the second one is called other.

As we can see above, we have replicated all the data source properties and given it a new prefix, other. Now, these two databases could have completely independent settings. They could point to totally different databases. Each of these properties could be configured to completely different settings. Here we have just changed the name of the database, username, password.
To make this work. we will have to split the repositories and the entity objects for each of the data sources. Here we create the following hierarchy of packages for each of the data sources.
src/main/java
- in.springframework.blog.tutorials
 - user
    - domain
    - repository
  - other
    - domain
    - repository
As we can see for each of the data sources, we have a domain package that would contain the entities and a repository package that would contain the repository class. This is needed so that each of the entity managers only searches for its own classes.
Now we need to define a configuration of each of the data sources that we have defined. The first data source will contain the user table and will also be the primary data source.

As we can see in the class above, it uses all the properties prefixed with spring.datasource and scans directories related to the user data source. Now let's look at the configuration for other data source.

The things to note in the other data source is that the @Primary annotation doesn't exist because we can have only one set of primary beans of a type. Also, the directories to be searched are for the other data source's domain and repository objects.
At this time we also move the old User and UserRepository classes to their respective subdirectories. We also create Other and OtherRepository classes in their respective subdirectories. We also change CrudRepository to JpaRepository in each of the repository classes.
Now, our application is set up to use two different data sources and we can verify that by running the application. Since we have set ddl-auto property to update, it should create a new schedule when the application is run.
$ mysql -u tutorial -ptutorial123 tutorial
mysql: [Warning] Using a password on the command line interface can be insecure.
Reading table information for completion of table and column names
You can turn off this feature to get a quicker startup with -A

Welcome to the MySQL monitor.  Commands end with ; or \g.
Your MySQL connection id is 115
Server version: 8.0.12 Homebrew

Copyright (c) 2000, 2018, Oracle and/or its affiliates. All rights reserved.

Oracle is a registered trademark of Oracle Corporation and/or its
affiliates. Other names may be trademarks of their respective
owners.

Type 'help;' or '\h' for help. Type '\c' to clear the current input statement.

mysql> show tables;
+--------------------+
| Tables_in_tutorial |
+--------------------+
| hibernate_sequence |
| user               |
+--------------------+
2 rows in set (0.00 sec)

mysql> desc user;
+------------+--------------+------+-----+---------+-------+
| Field      | Type         | Null | Key | Default | Extra |
+------------+--------------+------+-----+---------+-------+
| id         | bigint(20)   | NO   | PRI | NULL    |       |
| email      | varchar(255) | YES  | UNI | NULL    |       |
| fullname   | varchar(255) | YES  |     | NULL    |       |
| password   | varchar(255) | YES  |     | NULL    |       |
| username   | varchar(255) | YES  | UNI | NULL    |       |
| auth_token | varchar(255) | YES  | UNI | NULL    |       |
| expiry     | datetime     | YES  |     | NULL    |       |
| mask       | bigint(20)   | NO   |     | NULL    |       |
| authToken  | varchar(255) | YES  |     | NULL    |       |
+------------+--------------+------+-----+---------+-------+
9 rows in set (0.00 sec)

$ mysql -u other -pother123 other
mysql: [Warning] Using a password on the command line interface can be insecure.
Reading table information for completion of table and column names
You can turn off this feature to get a quicker startup with -A

Welcome to the MySQL monitor.  Commands end with ; or \g.
Your MySQL connection id is 116
Server version: 8.0.12 Homebrew

Copyright (c) 2000, 2018, Oracle and/or its affiliates. All rights reserved.

Oracle is a registered trademark of Oracle Corporation and/or its
affiliates. Other names may be trademarks of their respective
owners.

Type 'help;' or '\h' for help. Type '\c' to clear the current input statement.

mysql> show tables;
+--------------------+
| Tables_in_other    |
+--------------------+
| hibernate_sequence |
| other              |
+--------------------+
2 rows in set (0.00 sec)

mysql> desc other
    -> ;
+-----------+--------------+------+-----+---------+-------+
| Field     | Type         | Null | Key | Default | Extra |
+-----------+--------------+------+-----+---------+-------+
| id        | bigint(20)   | NO   | PRI | NULL    |       |
| otherData | varchar(255) | YES  |     | NULL    |       |
+-----------+--------------+------+-----+---------+-------+
2 rows in set (0.00 sec)
The source code for this tutorial is available at git repository as v1.2.

1 comment:

  1. curious why you'd want to use `@Value` rather than a more type-safe option as defined in the reference guide. There is also a section about multiple datasources (https://docs.spring.io/spring-boot/docs/current/reference/htmlsingle/#howto-two-datasources).

    ReplyDelete