2014-10-03 21 views
2

我在一個項目中使用Spring,Spring Data JPA,Spring Security,Primefaces ...如何使用具有動態數據源的Spring AbstractRoutingDataSource?

我跟隨this tutorial關於使用spring進行動態數據源路由。

在本教程中,您只能實現預定義數據源之間的動態數據源切換。

這裏是我的代碼片段:

springContext-jpa.xml

<bean id="dsCgWeb1" class="org.apache.commons.dbcp.BasicDataSource"> 
    <property name="driverClassName" value="${jdbc.driverClassName.Cargest_web}"></property> 
    <property name="url" value="${jdbc.url.Cargest_web}"></property> 
    <property name="username" value="${jdbc.username.Cargest_web}"></property> 
    <property name="password" value="${jdbc.password.Cargest_web}"></property> 
</bean> 

<bean id="dsCgWeb2" class="org.apache.commons.dbcp.BasicDataSource"> 
    // same properties, different values .. 
</bean> 

<!-- Generic Datasource [Default : dsCargestWeb1] --> 
<bean id="dsCgWeb" class="com.cargest.custom.CargestRoutingDataSource"> 
    <property name="targetDataSources"> 
     <map> 
      <entry key="1" value-ref="dsCgWeb1" /> 
      <entry key="2" value-ref="dsCgWeb2" /> 
     </map> 
    </property> 
    <property name="defaultTargetDataSource" ref="dsCgWeb1" /> 
</bean> 

什麼我想要做的就是讓targetDataSources地圖動態相同的元素了。

換句話說,我希望獲取某個特定數據庫表,使用存儲在該表中的屬性創建數據源我然後把它們放到一個地圖就像targetDataSources

有沒有辦法做到這一點?

+1

我有類似的功能來實現。在我的情況下,它是運行時創建的許多數據源,用戶,密碼和jdbc URL從'env'數據庫中讀取。所以我所做的就是創建我自己的DataSource接口實現,該接口保留靜態併發映射字段,用於存儲所有動態創建的數據源實例,以及用於保存特定線程正在使用的當前數據源信息的ThreadLocal變量。 – 2014-10-03 09:41:30

+0

你的解決方案沒有任何問題嗎?如果是這樣,這正是我需要的。你能提供你的自定義數據源實現嗎?謝謝:) – 2014-10-03 09:49:34

+0

當然,它的工作原理:)但我不能以現在的方式分享代碼。我會盡我所能將它簡化爲我可以分享它的形式,並將它放在github上並分享它的鏈接。 – 2014-10-03 10:11:36

回答

6

AbstractRoutingDataSource中沒有任何內容強制您使用DataSourceS的靜態地圖。您需要構建一個實現Map<Object, Object>的bean,其中關鍵是您用於選擇DataSource的值,值爲DataSource或(默認情況下)引用JNDI定義的數據源的String。您甚至可以動態修改它,因爲地圖存儲在內存中,因此AbstractRoutingDataSource不會進行緩存。

我沒有完整的示例代碼。但這是我能想象的。在一個Web應用程序中,每個客戶端都有一個數據庫,所有客戶端都具有相同的結構 - 好吧,這將是一個奇怪的設計,只是舉個例子。在登錄時,該應用程序爲客戶端創建並存儲在通過的sessionId索引的地圖數據源 - 地圖是在根上下文bean的命名dataSources

@Autowired 
@Qualifier("dataSources"); 
Map<String, DataSource> sources; 

// I assume url, user and password have been found from connected user 
// I use DriverManagerDataSource for the example because it is simple to setup 
DataSource dataSource = new DriverManagerDataSource(url, user, password); 
sources.put(request.getSession.getId(), dataSource); 

您還需要一個會話監聽清理dataSourcesdestroy方法

@Autowired 
@Qualifier("dataSources"); 
Map<String, DataSource> sources; 

public void sessionDestroyed(HttpSessionEvent se) { 
    // eventually cleanup the DataSource if appropriate (nothing to do for DriverManagerDataSource ...) 
    sources.remove(se.getSession.getId()); 
} 

路由數據源可能是這樣的:

public class SessionRoutingDataSource extends AbstractRoutingDataSource { 

    @Override 
    protected Object determineCurrentLookupKey() { 
     HttpServletRequest request = ((ServletRequestAttributes) 
       RequestContextHolder.getRequestAttributes()).getRequest(); 
     return request.getSession().getId(); 
    } 

    @Autowired 
    @Qualifier("dataSources") 
    public void setDataSources(Map<String, DataSource> dataSources) { 
     setTargetDataSources(dataSources); 
} 

我沒有測試任何因爲設置不同的數據庫需要很多工作,但是我應該確定它。在現實世界中,每個會話不會有不同的數據源,但每個用戶會有一個會話數量不同的用戶,但正如我所說的那樣,這是一個簡單的例子。

+1

你能提供一個示例代碼嗎? – 2014-10-05 22:34:11

相關問題