如何将 Spring AbstractRoutingDataSource 与动态数据源一起使用? [英] How to use Spring AbstractRoutingDataSource with dynamic datasources?
问题描述
我在一个使用 Spring、Spring Data JPA、Spring Security、Primefaces 的项目中工作...
I am working in a project using Spring, Spring Data JPA, Spring Security, Primefaces...
我正在关注关于动态数据源路由的本教程与春天.
I was following this tutorial about dynamic datasource routing with spring.
在本教程中,您只能实现预定义数据源之间的动态数据源切换.
In this tutorial, you can only achieve dynamic datasource switching between a pre-defined datasources.
这是我的代码片段:
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 映射动态与其元素相同.
What i want to do is to make the targetDataSources map dynamic same as its elements too.
换句话说,我想获取某个数据库表,使用存储在该表中的属性来创建我的数据源,然后将它们放在像 targetDataSources 这样的地图中.
In other words, i want to fetch a certain database table, use properties stored in that table to create my datasources then put them in a map like targetDataSources.
有没有办法做到这一点?
Is there a way to do this ?
推荐答案
AbstractRoutingDataSource
中没有任何内容强制您使用 DataSourceS
的静态映射.由你来构建一个实现 Map
的 bean,其中 key 是你用来选择 DataSource
的东西,value 是一个 DataSource
或(默认情况下)引用 JNDI 定义的数据源的字符串.您甚至可以动态修改它,因为地图存储在内存中,AbstractRoutingDataSource
不缓存.
Nothing in AbstractRoutingDataSource
forces you to use a static map of DataSourceS
. It is up to you to contruct a bean implementing Map<Object, Object>
, where key is what you use to select the DataSource
, and value is a DataSource
or (by default) a String referencing a JNDI defined data source. You can even modify it dynamically since, as the map is stored in memory, AbstractRoutingDataSource
does no caching.
我没有完整的示例代码.但这是我能想象的.在 Web 应用程序中,每个客户端都有一个数据库,所有数据库都具有相同的结构 - 好吧,这将是一种奇怪的设计,仅作为示例而已.在登录时,应用程序为客户端创建数据源并将其存储在由 sessionId 索引的映射中 - 该映射是名为 dataSources
I have no full example code. But here is what I can imagine. In a web application, you have one database per client, all with same structure - ok, it would be a strange design, say it is just for the example. At login time, the application creates the datasource for the client and stores it in a map indexed by sessionId - The map is a bean in root context named 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);
你还需要一个会话监听器来清理 dataSources
在它的 destroy
方法
You also need a session listener to cleanup dataSources
in its destroy
method
@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());
}
路由数据源可能是这样的:
The routing datasource could be like :
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);
}
我没有测试任何东西,因为设置不同的数据库需要做很多工作,但我认为应该没问题.在现实世界中,每个会话不会有不同的数据源,而是每个用户一个,每个用户都有一个会话数,但正如我所说,这是一个过于简化的例子.
I have not tested anything because it would be a lot of work to setting the different database, but I thing that it should be Ok. In real world there would not be a different data source per session but one per user with a count of session per user but as I said it is an over simplified example.
这篇关于如何将 Spring AbstractRoutingDataSource 与动态数据源一起使用?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!