spring动态创建数据源

Posted 一响贪欢

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了spring动态创建数据源相关的知识,希望对你有一定的参考价值。

项目业务,在程序的运行过程中,可能会存在新的数据库添链接加进来,从新数据库链接中读取数据。

spring为多数据源提供了一个抽象类AbstractRoutingDataSource,该类中只有一个抽象方法determineCurrentLookupKey()需要由我们实现。

 

假设我们创建一个类DynimaticDataSource,继承AbstractRoutingDataSource,并重写determineCurrentLookupKey()方法。

 

spring启动初始化DynimaticDataSource:

1、可以通过spring的自动注入,对AbstractRoutingDataSource类注入相应的属性,注入属性不是必须的,可以通过继承后重写方法来重设对这些属性的调用。

2、注入后spring会执行DynimaticDataSource中的protected方法afterPropertiesSet(),该方法先判断属性targetDataSources不能为null,否则抛出异常"Property ‘targetDataSources‘ is required"。然后将该属性(类型为map<object,object>)的值全部转换到属性resolvedDataSources(类型为map<Object, DataSource>)中去。如果属性defaultTargetDataSource不为null,将其转换为DataSource类型并赋值给属性defaultTargetDataSource。

经过以上处理后,属性resolvedDataSources中会被存放我们添加的数据源,该属性是一个map集合,key为Object类型,value为数据源。

 

使用DynimaticDataSource类:

1、调用该类的public方法getConnection()来获取连接。

2、getConnection被重写,方法中会先调用protected方法determineTargetDataSource()。该方法先判断属性resolvedDataSources不为null,否则抛出异常"DataSource router not initialized"。然后调用由子类重写的抽象方法determineCurrentLookupKey()获取dataSource在resolvedDataSources中对应的key。

3、根据key从resolvedDataSources中获取数据源,如果resolvedDataSources中不存在,再判断lenientFallback为true(默认为true,可以设置)或key为null,返回默认数据源resolvedDefaultDataSource。否则抛出异常"Cannot determine target DataSource for lookup key [" + key+ "]"。

4、调用获取数据源的getConnection()方法获取连接。

 

在初始化时指定多数据源案例代码:

1、创建一个类DynimaticDataSource,继承AbstractRoutingDataSource,并重写determineCurrentLookupKey()方法。该方法负责判断当前线程使用哪一种数据源。这是最简单的一种实现方法,不重写任何非抽象方法。

public class DynamicDatasource extends AbstractRoutingDataSource{

    private static Map<Object, Object> targetDataSources;
    
    protected DruidDataSource dataSource;
    
    @Override
    protected String determineCurrentLookupKey() {
      //指定使用哪个数据源
return DataSourceUtils.getDbtype(); } }

2、srping配置文件(部分)

    <bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource" destroy-method="close">
        <property name="url" value="${jdbc.url}" />
        <property name="username" value="${jdbc.username}" />
        <property name="password" value="${jdbc.password}" />
        <property name="driverClassName" value="${jdbc.driver}" />
        <property name="maxActive" value="50" /><!-- 最大连接池数 -->
        <property name="minIdle" value="5" /><!-- 最小连接池数 -->
    </bean>
    
    <bean id="dataSource2" class="com.alibaba.druid.pool.DruidDataSource" destroy-method="close">
        <property name="url" value="${jdbc.url2}" />
        <property name="username" value="${jdbc.username2}" />
        <property name="password" value="${jdbc.password2}" />
        <property name="driverClassName" value="${jdbc.driver}" />
        <property name="maxActive" value="50" /><!-- 最大连接池数 -->
        <property name="minIdle" value="5" /><!-- 最小连接池数 -->
    </bean>
    
    <bean id="multDataSource" class="com.ftpSystem.dao.DynamicDatasource">
        <property name="targetDataSources">
            <map >
                <entry value-ref="dataSource" key="masterDataSource"></entry>
                <entry value-ref="dataSource2" key="yangDataSource"></entry>
            </map>
        </property>
    <property name="defaultTargetDataSource" ref="dataSource"></property>
</bean>

3、使用数据源,我这里使用jdbcTemple,可以使用其他持久层框架,方式同单数据源配置一致。

    <bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
        <property name="dataSource" ref="multDataSource"></property>
    </bean>

4、切换数据源类

public class DataSourceUtils {

    private static final ThreadLocal<String> local = new ThreadLocal<String>();
    
    public static String getDbtype() {
        return local.get();
    }
    
    public static void setDbtype(String dbtype) {
        local.set(dbtype);
    }
    
    public static void clear() {
        local.remove();
    }
}

5、客户端代码

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration("classpath:applicationContext-dao.xml")
public class TestDao {

    @Autowired
    private JdbcTemplate jdbcTemplate;
    
    @Test
    public void Test(){
        System.out.println("ok");
        int i = (Integer) jdbcTemplate.queryForObject("select count(*) from t_gg_zsdw", Integer.class);
        System.out.println("i="+i);
        DataSourceUtils.setDbtype("dataSource2");//切换数据源至dataSource2
        i = (Integer) jdbcTemplate.queryForObject("select count(*) from t_gg_zsdw", Integer.class);
        System.out.println("i="+i);
    }
}

由于我们已经在spring的配置文件中指定了属性defaultTargetDataSource,因此程序会默认使用该数据源。然后我们执行一次后切换为dataSource2,之后的执行会改为使用dataSource2的数据源。

 

以上方式可以对程序配置多数据源,但是不方便之处在程序初始化之时就指定所有的数据源,无法运行时添加。

 

程序动态配置多数据源:

该方式与上一种的区别在于重写AbstractRoutingDataSource类的子类DynimaticDataSource

下班了,明天继续

 




以上是关于spring动态创建数据源的主要内容,如果未能解决你的问题,请参考以下文章

在android中动态创建选项卡并使用传入的参数加载片段

在动态 viewpager 片段中创建 recyclerviews

阿里四面:你知道Spring AOP创建Proxy的过程吗?

Spring boot:thymeleaf 没有正确渲染片段

为动态创建的 Android 片段提供自定义属性值

在 ViewPager 中使用视图创建动态片段