Spring boot Spring boot读写拆分/主-从/多个数据库
我正在关注这个链接 我已经实现了代码,但我的两个服务功能仍然使用相同的数据库(一个标记为primary) 服务等级Spring boot Spring boot读写拆分/主-从/多个数据库,spring-boot,spring-data-jpa,Spring Boot,Spring Data Jpa,我正在关注这个链接 我已经实现了代码,但我的两个服务功能仍然使用相同的数据库(一个标记为primary) 服务等级 public class TableService{ @Autowired private Table1Repo t1Repo; @Transactional(readOnly = false) public void saveTable1(Table1 t,int a, Table1 t2){ try{
public class TableService{
@Autowired
private Table1Repo t1Repo;
@Transactional(readOnly = false)
public void saveTable1(Table1 t,int a, Table1 t2){
try{
t1Repo.save(t2);
}
catch(Exception e){
System.out.println("Inside");
}
}
@Transactional(readOnly = true)
public Table1 getTable(int id){
return t1Repo.findOne(id);
}
}
然后添加了两个类(从链接)
复制路由数据源
public class ReplicationRoutingDataSource extends AbstractRoutingDataSource {
@Override
protected Object determineCurrentLookupKey() {
String dataSourceType = TransactionSynchronizationManager.isCurrentTransactionReadOnly() ? "read" : "write";
return dataSourceType;
}
}
使用路由数据源配置
@Configuration
public class WithRoutingDataSourceConfig {
/*@Bean(destroyMethod = "shutdown")*/
@Bean
@Primary
@ConfigurationProperties(prefix="datasource.primary")
public DataSource writeDataSource() {
/* EmbeddedDatabaseBuilder builder = new EmbeddedDatabaseBuilder()
.setName("routingWriteDb")
.setType(EmbeddedDatabaseType.H2)
.setScriptEncoding("UTF-8")
.addScript("classpath:/writedb.sql");
return builder.build();*/
return DataSourceBuilder.create().build();
}
/* @Bean(destroyMethod = "shutdown")*/
@Bean
@ConfigurationProperties(prefix="datasource.secondary")
public DataSource readDataSource() {
/*EmbeddedDatabaseBuilder builder = new EmbeddedDatabaseBuilder()
.setName("routingReadDb")
.setType(EmbeddedDatabaseType.H2)
.setScriptEncoding("UTF-8")
.addScript("classpath:/readdb.sql");
return builder.build();*/
return DataSourceBuilder.create().build();
}
/**
* {@link org.springframework.jdbc.datasource.lookup.AbstractRoutingDataSource}는
* {@link org.springframework.beans.factory.InitializingBean}을 구현하므로,
* 명시적으로 afterPropertiesSet()메소드를 호출하거나
* 별도 @Bean으로 만들어 Spring Life Cycle을 타도록 해야 한다.
*/
@Bean
public DataSource routingDataSource(@Qualifier("writeDataSource") DataSource writeDataSource, @Qualifier("readDataSource") DataSource readDataSource) {
ReplicationRoutingDataSource routingDataSource = new ReplicationRoutingDataSource();
Map<Object, Object> dataSourceMap = new HashMap<Object, Object>();
dataSourceMap.put("write", writeDataSource);
dataSourceMap.put("read", readDataSource);
routingDataSource.setTargetDataSources(dataSourceMap);
routingDataSource.setDefaultTargetDataSource(writeDataSource);
return routingDataSource;
}
/**
* {@link org.springframework.jdbc.datasource.LazyConnectionDataSourceProxy}로 감싸서
* 트랜잭션 동기화가 이루어진 뒤에 실제 커넥션을 확보하도록 해준다.
*
* @param routingDataSource
* @return
*/
@Bean
public DataSource dataSource(@Qualifier("routingDataSource") DataSource routingDataSource) {
return new LazyConnectionDataSourceProxy(routingDataSource);
}
}
存储库
public interface Table1Repo extends JpaRepository<Table1, Integer>{}
我是你提到的链接的作者 您在Table1Reporto中使用哪种数据源 您必须向JDBC调用注入特定的bean“数据源” 我猜
@Primary
“writeDataSource”被注入到您的存储库中
尝试将
@Primary
更改为“dataSource”,或找到将“dataSource”注入存储库的方法。您也可以通过以下方式尝试:
下面是github中的源代码:
下面的链接解释了如何拥有多个数据源
DB1(写入):
DB2(读取):
错误是什么?没有错误。它只是使用主数据库进行读写(对于我的两个服务功能),但我希望它使用diff DB进行基于注释的读写。我遇到了与您完全相同的问题(包括我将@primary放在LazyConnectionDataSourceProxy上的第一个周期。你能解释一下你的解决方案吗?我们为什么应该把这些bean放在哪里?我试着把它们放在与数据源相同的类中,但它不起作用。如果我将@primary添加到数据源中,这会使我错误地理解一些bean的依赖关系。)应用程序上下文中的bean形成一个循环:org.springframework.boot.autoconfigure.orm.jpa.HibernateJpaAutoConfiguration┌─────┐ | 在类路径资源[com/example/WithRoutingDataSourceConfig.class]中定义的数据源↑ ↓ | 在类路径资源[com/example/WithRoutingDataSourceConfig.class]中定义的routingDataSource↑ ↓ | 在类路径资源[com/example/WithRoutingDataSourceConfig.class]中定义的writeDataSource↑ ↓ | DataSourceInitializationeral虽然我已经通过上面的代码和添加一个配置类使代码正常工作。我已经更新了我的问题,请您检查它是否正确。此外,我的Table1Reporto将同时使用读写数据源。我相信您的第二个解决方案是可以的。但我仍然不理解为什么数据源配置是循环的。这可能是SpringBoot JPA自动配置的问题。我在Spring中使用此解决方案时没有任何问题。KwonNam:我在一个项目中工作&我有一个要求,我需要两个不同的数据库&我希望对这两个数据库进行读/写拆分?那么我是否要更改代码?如果我想在单个流中使用读写(调用),我该怎么做?既然determineLookUpKey只被调用了一次而不是更多,现在发生了什么?
public interface Table1Repo extends JpaRepository<Table1, Integer>{}
@Configuration
@EnableTransactionManagement
@EnableJpaRepositories(basePackages="com.example")
public class ReplicationDataSourceApplicationConfig {
@Bean
public LocalContainerEntityManagerFactoryBean entityManagerFactory(@Qualifier("dataSource") DataSource dataSource) {
LocalContainerEntityManagerFactoryBean emfb = new LocalContainerEntityManagerFactoryBean();
emfb.setDataSource(dataSource);
emfb.setPackagesToScan("com.example");
HibernateJpaVendorAdapter jpaVendorAdapter = new HibernateJpaVendorAdapter();
emfb.setJpaVendorAdapter(jpaVendorAdapter);
return emfb;
}
@Bean
public PlatformTransactionManager transactionManager(EntityManagerFactory entityManagerFactory) {
JpaTransactionManager transactionManager = new JpaTransactionManager();
transactionManager.setEntityManagerFactory(entityManagerFactory);
return transactionManager;
}
@Bean
public PersistenceExceptionTranslationPostProcessor exceptionTranslationPostProcessor() {
return new PersistenceExceptionTranslationPostProcessor();
}
}
@Configuration
@ConfigurationProperties("spring.datasource-write")
@EnableTransactionManagement
@EnableJpaRepositories(
entityManagerFactoryRef = "entityManagerFactoryWrite",
transactionManagerRef = "transactionManagerWrite",
basePackages = {"com.ehsaniara.multidatasource.repository.writeRepository"}
)
public class DataSourceConfigWrite extends HikariConfig {
public final static String PERSISTENCE_UNIT_NAME = "write";
@Bean
public HikariDataSource dataSourceWrite() {
return new HikariDataSource(this);
}
@Bean
public LocalContainerEntityManagerFactoryBean entityManagerFactoryWrite(
final HikariDataSource dataSourceWrite) {
return new LocalContainerEntityManagerFactoryBean() {{
setDataSource(dataSourceWrite);
setPersistenceProviderClass(HibernatePersistenceProvider.class);
setPersistenceUnitName(PERSISTENCE_UNIT_NAME);
setPackagesToScan(MODEL_PACKAGE);
setJpaProperties(JPA_PROPERTIES);
}};
}
@Bean
public PlatformTransactionManager transactionManagerWrite(EntityManagerFactory entityManagerFactoryWrite) {
return new JpaTransactionManager(entityManagerFactoryWrite);
}
}
@Configuration
@ConfigurationProperties("spring.datasource-read")
@EnableTransactionManagement
@EnableJpaRepositories(
entityManagerFactoryRef = "entityManagerFactoryRead",
transactionManagerRef = "transactionManagerRead",
basePackages = {"com.ehsaniara.multidatasource.repository.readRepository"}
)
public class DataSourceConfigRead extends HikariConfig {
public final static String PERSISTENCE_UNIT_NAME = "read";
@Bean
public HikariDataSource dataSourceRead() {
return new HikariDataSource(this);
}
@Bean
public LocalContainerEntityManagerFactoryBean entityManagerFactoryRead(
final HikariDataSource dataSourceRead) {
return new LocalContainerEntityManagerFactoryBean() {{
setDataSource(dataSourceRead);
setPersistenceProviderClass(HibernatePersistenceProvider.class);
setPersistenceUnitName(PERSISTENCE_UNIT_NAME);
setPackagesToScan(MODEL_PACKAGE);
setJpaProperties(JPA_PROPERTIES);
}};
}
@Bean
public PlatformTransactionManager transactionManagerRead(EntityManagerFactory entityManagerFactoryRead) {
return new JpaTransactionManager(entityManagerFactoryRead);
}
}