Read Replicas and Spring Data, Part 3: Configuring Two Entity Managers
Learn more about read replicas and Spring Data in this tutorial on how to configure two entity managers.
Join the DZone community and get the full member experience.
Join For FreeOur previous set-up works as expected. So what we shall do now is to get one step further and configure two separate entity managers without affecting the functionality we achieved previously.
Check out previous posts: Read Replicas and Spring Data, Part 1: Configuring the Databases & Read Replicas and Spring Data, Part 2: Configuring the Base Project
The first step would be to set the default entity manager configuration to a primary one.
This is the first step:
package com.gkatzioura.springdatareadreplica.config;
import javax.sql.DataSource;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.jdbc.DataSourceBuilder;
import org.springframework.boot.orm.jpa.EntityManagerFactoryBuilder;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Primary;
import org.springframework.data.jpa.repository.config.EnableJpaRepositories;
import org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean;
@Configuration
public class PrimaryEntityManagerConfiguration {
@Value("${spring.datasource.username}")
private String username;
@Value("${spring.datasource.password}")
private String password;
@Value("${spring.datasource.url}")
private String url;
@Bean
@Primary
public DataSource dataSource() throws Exception {
return DataSourceBuilder.create()
.url(url)
.username(username)
.password(password)
.driverClassName("org.postgresql.Driver")
.build();
}
@Bean
@Primary
public LocalContainerEntityManagerFactoryBean entityManagerFactory(
EntityManagerFactoryBuilder builder,
@Qualifier("dataSource") DataSource dataSource) {
return builder.dataSource(dataSource)
.packages("com.gkatzioura.springdatareadreplica")
.persistenceUnit("main")
.build();
}
}
If you run your application with this configuration, it will run just like our application previously.
Now, it is time to configure the read-only entity manager.
package com.gkatzioura.springdatareadreplica.config;
import javax.sql.DataSource;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.jdbc.DataSourceBuilder;
import org.springframework.boot.orm.jpa.EntityManagerFactoryBuilder;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Primary;
import org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean;
@Configuration
public class ReadOnlyEntityManagerConfiguration {
@Value("${spring.datasource.username}")
private String username;
@Value("${spring.datasource.password}")
private String password;
@Value("${spring.datasource.readUrl}")
private String readUrl;
@Bean
public DataSource readDataSource() throws Exception {
return DataSourceBuilder.create()
.url(readUrl)
.username(username)
.password(password)
.driverClassName("org.postgresql.Driver")
.build();
}
@Bean
public LocalContainerEntityManagerFactoryBean readEntityManagerFactory(
EntityManagerFactoryBuilder builder,
@Qualifier("readDataSource") DataSource dataSource) {
return builder.dataSource(dataSource)
.packages("com.gkatzioura.springdatareadreplica")
.persistenceUnit("read")
.build();
}
}
Also, I will add a method to a controller in order to save the models.
package com.gkatzioura.springdatareadreplica.controller;
import java.util.List;
import org.springframework.http.HttpStatus;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.ResponseStatus;
import org.springframework.web.bind.annotation.RestController;
import com.gkatzioura.springdatareadreplica.entity.Employee;
import com.gkatzioura.springdatareadreplica.repository.EmployeeRepository;
@RestController
public class EmployeeContoller {
private final EmployeeRepository employeeRepository;
public EmployeeContoller(EmployeeRepository employeeRepository) {
this.employeeRepository = employeeRepository;
}
@GetMapping("/employee")
public List<Employee> getEmployees() {
return employeeRepository.findAll();
}
@PostMapping("/employee")
@ResponseStatus(HttpStatus.CREATED)
public void addEmployee(@RequestBody Employee employee) {
employeeRepository.save(employee);
}
}
If you do try to add an employee using the controller and then query the read database, you shall see that no entry is being added at all.
So, we have our primary entity manager up and running, and we also have a secondary one. The secondary one is not used yet. The next blog focuses on putting the secondary read-only entity manager in use. Stay tuned!
Further Reading
Read Replicas and Spring Data, Part 1: Configuring the Databases
Read Replicas and Spring Data, Part 2: Configuring the Base Project
Published at DZone with permission of Emmanouil Gkatziouras, DZone MVB. See the original article here.
Opinions expressed by DZone contributors are their own.
Comments