Sunday, November 21, 2021

How to configure multiple database in Grails application

In this tutorial, we are going to learn how to configure multiple databases in the grails 3.x application. This is necessary when you are dealing with multiple databases from the same application especially when dealing with an existing remote database. We are using different MySql databases for testing.

Let's create three MySql databases called db_default, db_one, db_two. Let's look into the application.yml file to configure the different databases and we will do it for the development environment, in other environments, the procedure will be the same.


environments:
    development:
        dataSource:
            dbCreate: update
            url: jdbc:mysql://localhost:3306/db_default
            driverClassName: com.mysql.jdbc.Driver
            dialect: org.hibernate.dialect.MySQL5InnoDBDialect
            username: root
            password: root
Here, we are setting the default database as db_default. So for this database, all the gorm queries will be the same as in a normal application.

Now, let's set up for other two databases.
        dataSources:
            first:
                dialect: org.hibernate.dialect.MySQLInnoDBDialect
                driverClassName: com.mysql.jdbc.Driver
                username: root
                password: root
                url: jdbc:mysql://localhost:3306/db_one
                dbCreate: update
            second:
                dialect: org.hibernate.dialect.MySQLInnoDBDialect
                driverClassName: com.mysql.jdbc.Driver
                username: root
                password: root
                url: jdbc:mysql://localhost:3306/db_two
                dbCreate: update

For more than two, we need to define the databases by defining dataSources and giving the corresponding names. Here the custom name is whatever name you want. We are giving the name first for db_one and second for db_two.

The overall implementation for application.yml file looks as below:
environments:
    development:
        dataSource:
            dbCreate: update
            url: jdbc:mysql://localhost:3306/db_default
            driverClassName: com.mysql.jdbc.Driver
            dialect: org.hibernate.dialect.MySQL5InnoDBDialect
            username: root
            password: root
        dataSources:
            first:
                dialect: org.hibernate.dialect.MySQLInnoDBDialect
                driverClassName: com.mysql.jdbc.Driver
                username: root
                password: root
                url: jdbc:mysql://localhost:3306/db_one
                dbCreate: update
            second:
                dialect: org.hibernate.dialect.MySQLInnoDBDialect
                driverClassName: com.mysql.jdbc.Driver
                username: root
                password: root
                url: jdbc:mysql://localhost:3306/db_two
                dbCreate: update
Now, how we can use the domain classes for the specific databases. Let's create a simple domain class called Book.groovy.
class Book {
    String title
    
    static mapping = {
        datasource 'first' 
    }
}
In the above example, the Book table is mapped to the db_one database so all operations regarding this will be in db_one database. Similarly, we can map the second database as well. We can map the single domain to multiple databases as below:
class Book {
    String title
    
    static mapping = {
        datasources([ConnectionSource.DEFAULT, 'first', 'second'])
    }
}
In the above example, the Book domain will be available in all the databases.

Now, let's look into how we can query for the specific database.

The first DataSource specified is the default when not using an explicit namespace, so in this case, the default one is used. But you can call GORM methods on the 'first' or 'second' DataSource with the DataSource name, for example:
def book = Book.first.get(1) // this will get from db_one
book.first.save() //this will save in db_one
def book = Book.second.get(1) // this will get from db_two
book.second.save() // this will save in db_two
def book = Book.get(1) // this will get from db_default
book.save() // this will save in db_default

We can use groovy native SQL as well. Let's look at the example. 
import grails.transaction.Transactional
import groovy.sql.Sql
import org.springframework.beans.factory.annotation.Autowired
import org.springframework.beans.factory.annotation.Qualifier

import javax.sql.DataSource

@Transactional
class DbOneService {

    @Autowired
    @Qualifier('dataSource_first')
    DataSource dataSource

    def test() {
        def sql = new Sql(dataSource)
        def rows = sql.rows("select * from....")
        println "rows: "+rows
    }
}
Here, we are creating the DbOneService which is annotated with Qualifier where the db_one database name is configured as dataSource_first. This will provide the db_one database connection to do DB operation. You can simply execute the native SQL command as shown above. Similarly, we can do the same for the second database called db_two.
import grails.transaction.Transactional
import groovy.sql.Sql
import org.springframework.beans.factory.annotation.Autowired
import org.springframework.beans.factory.annotation.Qualifier

import javax.sql.DataSource

@Transactional
class DbTwoService {

    @Autowired
    @Qualifier('dataSource_second')
    DataSource dataSource

    def test() {
        def sql = new Sql(dataSource)
        def rows = sql.rows("select * from....")
        println "rows: "+rows
    }
}
This way, we can deal with multiple databases.
Share:

0 comments: