Read-only and read-write segregation in Spring / J2EE applications

We are using Spring, Spring-Data and JPA in our project.

For production servers, we would like to set up the database cluster so that all read requests are directed to one server and all write requests are directed to another server.

This will obviously require some changes in the way the DAO is created.

Does anyone know how to achieve this if so far have been working with DAO creation with Spring-Data / JPA, where the DAO implementation is responsible for reading and writing? What architectural changes would be required to separate the two types of calls?

+3


source to share


2 answers


When using MySQL, Java developers usually use Connector / J as the JDBC driver (as this is the official JDBC driver from MySQL). Developers usually use a class com.mysql.jdbc.Driver

as a driver with a url eg jdbc:mysql://host[:port]/database

.

The / J connector offers another driver called ReplicationDriver that allows an application to load balance across multiple MySQL hosts. When used ReplicationDriver

, the JDBC URL changes to jdbc:mysql:replication://master-host[:master-port][,slave-1-host[:slave-1-port]][,slave-2-host[:slave-2-port]]/database

. This allows the application to connect to one of several servers, depending on which one is available at any given time.

When used ReplicationDriver

, if JDBC connection is set to read-only

, the driver treats the first host declared in the URL as host read-write

and all others as read-only

. Developers can take advantage of this in a Spring application by structuring their code like this:



@Service
@Transactional(readOnly = true)
public class SomeServiceImpl implements SomeService {
   public SomeDataType readSomething(...) { ... }

   @Transactional(readOnly = false)
   public void writeSomething(...) { ... }
}

      

With code like this, whenever a method is called readSomething

, the Spring transaction control code will get the JDBC Connection

and invoke setReadOnly(true)

on it, because by default the service methods are annotated with.This @Transactional(readOnly = true)

will cause all database requests from the method to readSomething

go to one from non-master MySQL hosts, load balanced in round robin mode. Likewise, whenever called writeSomething

, Spring calls setReadOnly(false)

on the underlying JDBC Connection

, forcing the database requests to go to the main server.

This strategy allows the application to direct all read-only traffic to one set of MySQL servers and all read and write traffic to another server without changing the logical architecture of the application, or developers have to worry about different database nodes and roles.

+10


source


Ok, what you are talking about is actually called CQRS ( http://martinfowler.com/bliki/CQRS.html ). I would suggest reading some of the conceptual principles before attempting to implement it.

As for your question, for a brief first win, I would suggest starting to split the DAL services into Finder classes and Repository classes to be used by higher business oriented services.

Crawlers are suitable for read-only access, exposing only getBy ... () methods and search queries that return custom result objects, such as reports and their underlying implementation, for working with a read-only database.



Stores, on the other hand, will conform to write-only / getById () methods, and their underlying implementation is designed to work with a write-only database.

All that remains is synchronization between these databases. This can be achieved quite simply with technical solutions such as: database replication, deferred updates to a read-only database after making changes to a write-only database (possible consistency).

+2


source







All Articles