2017-04-13 73 views
0

好吧,我已經閱讀了很多關於此的帖子,並閱讀了關於此的spring引導文檔,但從未真正得到過更簡潔的答案。以非常乾淨的方式在Spring引導中配置兩個數據源

這裏我的用例:我們有100-200個oracle實體,我們使用JPARepository接口來查詢它們。現在我們需要確保讀數據庫用於讀取調用,寫入數據庫應該用於任何寫入。

我們有一個spring啓動應用程序,使用HikariCP數據源並使用@EnableTransactionManagement,@EnableJpaRepositories配置它,傳遞實體管理器,事務管理器和基本包的引用以進行掃描。

我已經創建了兩個配置文件,一個使用ReadConfiguration,一個使用WriteConfiguration。現在的問題是,我們有標準OO方式的代碼,我們有服務和存儲庫層。不同的服務正在注入各種存儲庫。每個存儲庫接口都在擴展JpaRepository,並且該接口在很多服務類中都是自動裝配的。

我想要實現的是使用相同的存儲庫層,但不知何故,存儲庫層應自動知道如果它是讀取調用,則使用讀取數據源,如果它是寫入調用,則使用寫入數據源。

其中一個解決方案是使用某種方法來破解代碼庫的代碼實現,以便有一些邏輯來查看它是否是讀取調用,然後使用此讀取數據源(如果它是寫入調用,然後使用寫入數據源)。有沒有人以這種方式解決這個問題?基本上我需要的是根據方法調用將調用路由到數據源。如果方法正在做一些讀取操作,那麼我需要確保它使用讀取數據源或使用寫入數據源。

任何人都可以指出如何實現這種架構的某些方向,而無需編寫用於讀寫的新存儲庫層。

感謝。

+0

@Oliver基爾克你有什麼婆感謝! – Coder

回答

0

我想你可以使用本回購中提到的AbstractRoutingDataSource。 https://github.com/kwon37xi/replication-datasource

使用這種方法,你可以添加@Transactional方法和額外的屬性來指示它的讀或寫。 @Transactional(readOnly = true | false)

+0

粗略地看着它,這樣我需要更新像100-200服務層添加事務註釋,我試圖避免。相反,我會做的是添加幾個新的類,可以完成工作。我們也使用HikariCP數據源不確定是否可以使用上面的方法來派生Spring JDBC類。 – Coder

+0

另外在某些情況下,一個服務方法正在進行讀取調用,然後編寫調用。所以在這種情況下,我需要在這種服務方法上使用寫入數據源。 – Coder

0

我不認爲這實際上是可能的(見下文),但這種方法至少可以接近。

我會從LazyConnectionDataSource的代碼開始,因爲由於您的要求,在您實際知道要使用它之前,您一定不能獲得連接。

給它一個參考會話,所以當它實際上需要一個Connection它檢查會話,看看它是否髒,並根據實際DataSource使用的決定。

現在爲什麼我不認爲這將實際工作。在正常使用情況下的交易包括:

  1. 閱讀一些數據

  2. 做基於它

  3. 堅持這些變化的一些變化。

這些步驟發生的順序嚴格,雖然我們有類型,比如Future在Java中,我們實際上並不能預知未來,因此無法在第一步,以決定是否會有第三步。

+0

感謝您的回覆。然後,我想我需要爲不同的存儲庫註冊不同的實體管理器,也就是說,我將爲正在執行任何寫入操作的存儲庫定義的數據源(寫入數據源可以讀取以及),並讀取正在讀取數據源的存儲庫的數據源。我猜想這會更容易。 – Coder

0

我的猜測是,這可能被看作是一個多租戶方式,一個租戶將只讀,其他租戶將

的步驟來配置持久層爲多租戶支持包括:

  • 休眠,JPA和數據源的性質。喜歡的東西:

application.yml

... 
multitenancy: 
    dvdrental: 
    dataSources: 
     - 
     tenantId: readonly 
     url: jdbc:postgresql://172.16.69.133:5432/db_dvdrental 
     username: user_dvdrental 
     password: changeit 
     driverClassName: org.postgresql.Driver 
     - 
     tenantId: write 
     url: jdbc:postgresql://172.16.69.133:5532/db_dvdrental 
     username: user_dvdrental 
     password: changeit 
     driverClassName: org.postgresql.Driver 
... 

MultiTenantJpaConfiguration.java

... 
@Configuration 
@EnableConfigurationProperties({ MultiTenantDvdRentalProperties.class, JpaProperties.class }) 
@ImportResource(locations = { "classpath:applicationContent.xml" }) 
@EnableTransactionManagement 
public class MultiTenantJpaConfiguration { 

    @Autowired 
    private JpaProperties jpaProperties; 

    @Autowired 
    private MultiTenantDvdRentalProperties multiTenantDvdRentalProperties; 
... 
} 

MultiTenantDvdRentalProperties.java

... 
@Configuration 
@ConfigurationProperties(prefix = "multitenancy.dvdrental") 
public class MultiTenantDvdRentalProperties { 

    private List<DataSourceProperties> dataSourcesProps; 
    // Getters and Setters 

    public static class DataSourceProperties extends org.springframework.boot.autoconfigure.jdbc.DataSourceProperties { 

    private String tenantId; 
    // Getters and Setters 
    } 
} 
  • 數據源豆

MultiTenantJpaConfiguration.java

... 
public class MultiTenantJpaConfiguration { 
... 
    @Bean(name = "dataSourcesDvdRental") 
    public Map<String, DataSource> dataSourcesDvdRental() { 
     ... 
    } 
... 
} 
  • 實體管理器工廠豆

MultiTenantJpaConfiguration.java

... 
public class MultiTenantJpaConfiguration { 
... 
    @Bean 
    public MultiTenantConnectionProvider multiTenantConnectionProvider() { 
     ... 
    } 

    @Bean 
    public CurrentTenantIdentifierResolver currentTenantIdentifierResolver() { 
     ... 
    } 

    @Bean 
    public LocalContainerEntityManagerFactoryBean entityManagerFactoryBean(MultiTenantConnectionProvider multiTenantConnectionProvider, 
    CurrentTenantIdentifierResolver currentTenantIdentifierResolver) { 
     ... 
    } 
... 
} 
  • 事務管理豆

MultiTenantJpaConfiguration.java

... 
public class MultiTenantJpaConfiguration { 
... 
    @Bean 
    public EntityManagerFactory entityManagerFactory(LocalContainerEntityManagerFactoryBean entityManagerFactoryBean) { 
     ... 
    } 

    @Bean 
    public PlatformTransactionManager txManager(EntityManagerFactory entityManagerFactory) { 
     ... 
    } 
... 
} 
  • 春天JPA的數據和事務支持配置

applicationContent.xml

... 
<jpa:repositories base-package="com.asimio.dvdrental.dao" transaction-manager-ref="txManager" /> 
<tx:annotation-driven transaction-manager="txManager" proxy-target-class="true" /> 
... 

ActorDao。java的

public interface ActorDao extends JpaRepository<Actor, Integer> { 
} 

根據您的需求這樣的事情可以做:

... 
@Autowired 
private ActorDao actorDao; 
... 

// Read feature 
... 
DvdRentalTenantContext.setTenantId("readonly"); 
this.actorDao.findOne(...); 
... 

// Or write 
DvdRentalTenantContext.setTenantId("write"); 
this.actorDao.save(...); 
... 

設置tenantId可以在Servlet過濾器/ Spring MVC的攔截器/線程將要執行的JPA完成操作等

大約多租戶方式的更多細節可以在我的博客上找到在http://tech.asimio.net/2017/01/17/Multitenant-applications-using-Spring-Boot-JPA-Hibernate-and-Postgres.html

相關問題