以前,我们在同一应用程序中设置了两个EntityManager。 一种用于读取,另一种用于写入。 现在是时候创建我们的读取存储库了。
只读存储库将使用辅助只读EntityManager。
为了使其成为只读存储库,至关重要的是不要执行任何保存和持久操作。
package com.gkatzioura.springdatareadreplica.repository; import java.util.List; import org.springframework.data.repository.Repository; import com.gkatzioura.springdatareadreplica.config.ReadOnlyRepository; import com.gkatzioura.springdatareadreplica.entity.Employee; /**
* This is a read only repository
*/ public interface ReadEmployeeRepository extends Repository {
List findAll(); }
我们的下一个任务是使用读取数据库实体管理器创建此存储库。
这意味着除只读存储库外,所有存储库均应使用默认实体管理器创建。
我将首先创建一个注释。 此注释将声明我的存储库为只读。 另外,我将使用此批注进行扫描操作,以便使用适当的EntityManager。
package com.gkatzioura.springdatareadreplica.config; import java.lang.annotation.Documented; import java.lang.annotation.ElementType; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; @Retention (RetentionPolicy.RUNTIME) @Target ({ElementType.TYPE}) @Documented public @interface ReadOnlyRepository { }
现在,我知道Spring Boot消除了对注释的需求,并以自动化的方式创建了存储库,但是我们的案例很特殊。
通过进行一些调整,我们的只读存储库将如下所示
package com.gkatzioura.springdatareadreplica.repository; import java.util.List; import org.springframework.data.repository.Repository; import com.gkatzioura.springdatareadreplica.config.ReadOnlyRepository; import com.gkatzioura.springdatareadreplica.entity.Employee; /**
* This is a read only repository
*/ @ReadOnlyRepository public interface ReadEmployeeRepository extends Repository {
List findAll(); }
现在是时候使用我们的存储库扫描了。 除使用@ReadOnlyRepository批注进行注释的存储库外,所有存储库均将注入主EntityManager。
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 @EnableJpaRepositories (
basePackages = "com.gkatzioura" ,
excludeFilters = @ComponentScan .Filter(ReadOnlyRepository. class ),
entityManagerFactoryRef = "entityManagerFactory" ) 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();
} }
同样,我们将为只读存储库添加配置。
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.data.jpa.repository.config.EnableJpaRepositories; import org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean; @Configuration @EnableJpaRepositories (
basePackages = "com.gkatzioura" ,
includeFilters= @ComponentScan .Filter(ReadOnlyRepository. class ),
entityManagerFactoryRef = "readEntityManagerFactory" ) 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();
} }
辅助实体管理器将仅注入仅具有@ReadOnlyRepository批注的存储库。
为了说明这一点,让我们对控制器进行一些更改。
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; import com.gkatzioura.springdatareadreplica.repository.ReadEmployeeRepository; @RestController public class EmployeeContoller {
private final EmployeeRepository employeeRepository;
private final ReadEmployeeRepository readEmployeeRepository;
public EmployeeContoller(EmployeeRepository employeeRepository,
ReadEmployeeRepository readEmployeeRepository) {
this .employeeRepository = employeeRepository;
this .readEmployeeRepository = readEmployeeRepository;
}
@GetMapping ( "/employee" )
public List getEmployees() {
return employeeRepository.findAll();
}
@GetMapping ( "/employee/read" )
public List getEmployeesRead() {
return readEmployeeRepository.findAll();
}
@PostMapping ( "/employee" )
@ResponseStatus (HttpStatus.CREATED) @ResponseStatus (HttpStatus.CREATED)
public void addEmployee( @RequestBody Employee employee) {
employeeRepository.save(employee);
} }
当您将员工添加到系统时,只读存储库将继续获取旧员工,而主存储库将获取所有员工,包括最近保留的员工。