2015-05-16 54 views
2

我現在已經在數據庫2個表:AbstractRoutingDataSource變化圖在運行時

  1. 用戶
  2. user_database

在用戶I存儲登錄名,密碼,角色
在user_database我存儲數據庫驅動程序,網址,密碼和用戶。 圖數據庫 enter image description here

我想用戶登錄到我的頁面和下一個連接,他所做的將被髮送到用戶數據庫。爲什麼我需要什麼?我計劃地圖流行的電子商務,並創建Android應用程序,用戶登錄並查看商店數據,可以添加和查看產品訂單。
現在是時候去練習了,我在彈簧技術方面的知識很少,請在我做錯事情時向我解釋一些事情。 AbstractRoutingDataSource的所有示例都在持久性文件中聲明瞭數據源或創建了數據源bean,並使用AbstractRoutingDataSource開始。 在我的項目中,我現在不用用戶連接,我需要從數據庫中獲取此信息。我試着得到使用知識庫和這個例子 https://stackoverflow.com/a/17575648/3037869 但我在控制器@Autowired null,我認爲庫的連接爲null。如何設置此存儲庫的連接並設置Route?缺陷是當我添加用戶時,我需要重新啓動服務器來刷新連接。
接下來嘗試我現在​​使用的是類User實施UserDetails用戶登錄後,我可以從getPrincipal()獲得用戶連接並添加到地圖。

private void setDataSources() { 
    HashMap<Object, Object> targetDataSources = new HashMap<>(); 
    DataSourceBuilder dataSourceBuilder = DataSourceBuilder.create(); 
    dataSourceBuilder.driverClassName("org.h2.Driver"); 
    dataSourceBuilder.url("jdbc:h2:mem:AZ;DB_CLOSE_DELAY=-1;DB_CLOSE_ON_EXIT=FALSE"); 
    dataSourceBuilder.username("sa"); 
    dataSourceBuilder.password(""); 
    targetDataSources.put("auth", dataSourceBuilder.build()); 
    setDefaultTargetDataSource(dataSourceBuilder.build()); 
    if(SecurityContextHolder.getContext().getAuthentication()!=null) { 
     User user=(User) SecurityContextHolder.getContext().getAuthentication().getPrincipal(); 
     System.out.println(user.getUserDatabase().getDriver()); 
     dataSourceBuilder.driverClassName(user.getUserDatabase().getDriver()); 
     dataSourceBuilder.url(user.getUserDatabase().getUrl()); 
     dataSourceBuilder.username("3450_Menadzer"); 
     dataSourceBuilder.password(user.getUserDatabase().getPassword()); 
     targetDataSources.put("user", dataSourceBuilder.build()); 
    } 
    setTargetDataSources(targetDataSources); 
    afterPropertiesSet(); //map is refresh when i add this 

} 

我運行constuctor這種方法determineCurrentLookupKey

protected Object determineCurrentLookupKey() { 
     if(SecurityContextHolder.getContext().getAuthentication()!=null) { 
      setDataSources(); 

      return "user"; 
     } 

     return "auth"; 
} 

這是工作,但是當我刷新3-4次的用戶數據庫中請求我讓

User 3450_Menadzer already has more than 'max_user_connections' active connections 

設置連接地圖manualy而不是刷新每個方法determineCurrentLookupKey運行我沒有這個問題。我認爲我的方法不是混淆連接。我如何清理這個?這可能更好的方法來路由連接?

編輯 @SergeBallesta我改變了一些代碼,從你的例子 這是我在地圖

@Component 
@Scope(value = "singleton") 
public class DataSourceMap { 
    private Map<Object,Object> dataSourceMap; 
    public DataSourceMap() 
    { 
     DataSourceBuilder dataSourceBuilder = DataSourceBuilder.create(); 
     dataSourceBuilder.driverClassName("org.h2.Driver"); 
     dataSourceBuilder.url("jdbc:h2:mem:AZ;DB_CLOSE_DELAY=-1;DB_CLOSE_ON_EXIT=FALSE"); 
     dataSourceBuilder.username("sa"); 
     dataSourceBuilder.password(""); 
     dataSourceMap=new HashMap<Object,Object>(); 
     dataSourceMap.put("auth",dataSourceBuilder.build()); 
    } 
    public void addDataSource(String session,DataSource dataSource) 
    { 
     this.dataSourceMap.put(session,dataSource); 
    } 
    public Map<Object,Object> getDataSourceMap() 
    { 
     return dataSourceMap; 
    } 
    public void removeSource(String session) 
    { 
     dataSourceMap.remove(session); 
    } 
} 

AbstractRoutingDataSource我做了一些改變,我是加afterPropertiesSet()怎麼一回事,因爲數據源不刷新。我做了一些刷新,我沒有得到錯誤,我認爲這是工作。我需要測試這個更多的數據庫在未來

@Component 
public class CustomRoutingDataSource extends AbstractRoutingDataSource{ 
    @Autowired 
    DataSourceMap dataSources; 
    @Override 
    protected Object determineCurrentLookupKey() { 
     setDataSources(dataSources); 
     afterPropertiesSet(); 
     System.out.println("test"); 
     if(SecurityContextHolder.getContext().getAuthentication()!=null) { 
      HttpServletRequest request = ((ServletRequestAttributes) 
        RequestContextHolder.getRequestAttributes()).getRequest(); 
      return request.getSession().getId(); 
     } 

     return "auth"; 
    } 
    @Autowired 
    public void setDataSources(DataSourceMap dataSources) { 
     System.out.println("data adding"); 
     setTargetDataSources(dataSources.getDataSourceMap()); 
    } 

} 
+0

你能分享你的代碼嗎?我在用戶登錄後擁有相同的任務,連接到一個基本數據庫並獲取數據源,然後將CRUD添加到數據源中!但我在Spring Framework中很新,我試了一個月,但沒有好的結果。我希望你的代碼能幫助我。 – mikezang

回答

2

首先,每個用戶數據庫是一個非常罕見的設計。如果所有這些數據庫都以相同的結構結束,請不要在真實世界的應用程序中這樣做,而只需在您的表和查詢中添加user_id。

接下來,我發現我的another answer中的動態AbstractRoutingDataSource的另一個(未完整)示例。

我的代碼(注意從未測試過)和你的問題之間的一個很大的區別是我使用SessionListener關閉數據庫以避免開放數據庫的數量無限增長。

如果你對這個學習春天,你可以試試下面的模式(自下而上說明):

  • 會話範圍的bean,將保持用戶實際的數據庫連接,連接應在第一次請求時創建(確保用戶ID存在於會話中)並進行緩存以供後續使用。一個銷燬方法(當session關閉時由Spring調用automaticaly)應該關閉連接。
  • AbstractRoutingDataSource,這將與代理上述持有人被注入,這將要求實際的數據源持有人

正如在其他的答案,如果同一用戶可能有很多併發會話,你可以在會話持有者中注入一個單例,以保持實際的數據庫連接以及活動會話的數量。這樣,每個用戶都可以獲得一個連接,無論他有多少個併發會話。

+0

我看着你的舊例子,我認爲這是可能的,但你需要我解釋一些東西。 'sessionDestroyed'方法在類中實現了'HttpSessionListener'嗎?你在哪裏執行'AbstractRoutingDataSource'這是compoment?添加連接數據庫在servlet上下文中還是類中? – seti

+0

@seti:我稍微修改了我的舊例子。這個想法是,map userId - > dataSource是在AbstractRoutingDataSource實現中注入的單例bean,在HttpSessionListener中將關閉數據源並將它們從地圖中刪除。你可以找到[這裏](http://stackoverflow.com/a/182203/3545273)成功登錄事件的監聽器的一個例子,它可以將數據庫存儲在地圖中 –

+0

我編輯我的問題你的邏輯幫助我。你能解釋一下我的舊代碼和新代碼(這是否正在工作)中的差異。在舊代碼中,我創建了dataSource映射集和刷新,在新的我從'@ Autowired'類設置和刷新獲取數據源。 – seti