我正在使用Spring,Spring Data JPA,Spring Security,Primefaces的项目中工作…
在本教程中,你只能在预定义的数据源之间实现动态数据源切换。
这是我的代码的片段:
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之类的映射中。
有没有办法做到这一点 ?
没有任何AbstractRoutingDataSource强制你使用的静态映射DataSourceS。构造一个bean实现由你自己决定Map<Object, Object>,其中key是用来选择的DataSource,而value是一个DataSource或(默认情况下)引用JNDI定义的数据源的String。你甚至可以动态修改它,因为当映射存储在内存中时,AbstractRoutingDataSource不进行缓存。
AbstractRoutingDataSource
Map<Object, Object>
我没有完整的示例代码。但是这是我可以想象的。在Web应用程序中,每个客户端都有一个数据库,所有数据库都具有相同的结构-好的,这是一个奇怪的设计,说它只是用于示例。在登录时,应用程序为客户端创建数据源并将其存储在由sessionId索引的映射中-该映射是根上下文中的Bean,名为dataSources
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方法
destroy
@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); }
我没有进行任何测试,因为设置不同的数据库需要大量工作,但我认为应该没问题。在现实世界中,每个会话不会有不同的数据源,而每个用户会有一个数据源,每个用户都有会话计数,但是正如我所说的,这是一个过于简化的示例。