如何将Spring AbstractRoutingDataSource与动态数据源一起使用? [英] How to use Spring AbstractRoutingDataSource with dynamic datasources?

查看:151
本文介绍了如何将Spring AbstractRoutingDataSource与动态数据源一起使用?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在使用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<Object, Object>的bean,其中key是用来选择DataSource的键,值是DataSource或(默认情况下)一个引用JNDI定义的数据源的String.您甚至可以动态修改它,因为当映射存储在内存中时,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);

您还需要一个会话侦听器以其destroy方法清理dataSources

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屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆