以前,我们在同一应用程序中设置了两个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); } }
当您将员工添加到系统时,只读存储库将继续获取旧员工,而主存储库将获取所有员工,包括最近保留的员工。
翻译自: https://www.javacodegeeks.com/2019/10/read-replicas-and-spring-data-configuring-the-read-repository.html