Spring 更改数据源连接url运行时

Spring 更改数据源连接url运行时,spring,hibernate,datasource,connection-pooling,Spring,Hibernate,Datasource,Connection Pooling,我正在从事一个使用spring+hibernate+mysql和c3p0进行连接池的项目 当前,连接池的属性是通过在src外部定义的属性加载的。(例如:${db_uname}) 当我们创建SpringBean时,一切都很好 由于某种原因,我们所连接的数据库可能无法访问,因此我们希望切换主机 需要实现回调,即连接到新主机并重新初始化池 任何关于如何优雅地覆盖现有数据源/连接池的指针都会大有帮助 下面是我的spring配置文件的样子 <?xml version="1.0" encoding="

我正在从事一个使用spring+hibernate+mysql和c3p0进行连接池的项目

当前,连接池的属性是通过在src外部定义的属性加载的。(例如:${db_uname})

当我们创建SpringBean时,一切都很好

由于某种原因,我们所连接的数据库可能无法访问,因此我们希望切换主机

需要实现回调,即连接到新主机并重新初始化池

任何关于如何优雅地覆盖现有数据源/连接池的指针都会大有帮助

下面是我的spring配置文件的样子

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:tx="http://www.springframework.org/schema/tx"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:util="http://www.springframework.org/schema/util"
xsi:schemaLocation="
    http://www.springframework.org/schema/beans 
    http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
    http://www.springframework.org/schema/tx 
    http://www.springframework.org/schema/tx/spring-tx-3.0.xsd
    http://www.springframework.org/schema/context 
    http://www.springframework.org/schema/context/spring-context-3.0.xsd
    http://www.springframework.org/schema/util
    http://www.springframework.org/schema/util/spring-util-3.0.xsd">

<!-- Component scans -->
<import resource="component-scans-1.xml" />
<import resource="component-scans-2.xml" />


<util:properties id="serviceManagerProperties" 
    location="classpath:servicemanagers.properties" />

<!-- Properties file -->
<context:property-placeholder location="classpath:database.config.properties,classpath:framework.properties" />

<!-- context:annotation-config / -->
<tx:annotation-driven transaction-manager="transactionManager" />

<bean id="dataSource"
    class="org.springframework.jdbc.datasource.DriverManagerDataSource">
</bean>

<bean id="transactionManager" class="org.springframework.orm.jpa.JpaTransactionManager">
    <property name="entityManagerFactory" ref="entityManagerFactory" />
</bean>

<context:mbean-server id="mbeanServer" />
<context:mbean-export server="mbeanServer" default-domain="a.b.c" />

<bean id="cacheManager" factory-method="getInstance"
    class="net.sf.ehcache.CacheManager" />

<bean class="net.sf.ehcache.management.ManagementService" init-method="init">
    <constructor-arg ref="cacheManager" />
    <constructor-arg ref="mbeanServer" />
    <constructor-arg value="false" />
    <constructor-arg value="false" />
    <constructor-arg value="false" />
    <constructor-arg value="true" />
</bean>

<bean id="entityManagerFactory"
    class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
    <property name="dataSource" ref="dataSource" />
    <property name="jpaVendorAdapter" ref="jpaAdapter" />
    <property name="persistenceXmlLocation" value="classpath*:META-INF/framework-persistence.xml" />
    <property name="persistenceUnitName" value="PU-NAME" />
    <property name="jpaProperties">
        <props>
            <prop key="hibernate.format_sql">true</prop>
            <prop key="hibernate.dialect">org.hibernate.dialect.MySQLDialect</prop>
            <prop key="hibernate.cache.use_query_cache">${hibernate.cache.use_query_cache}</prop>
            <prop key="hibernate.cache.use_second_level_cache">${hibernate.cache.use_second_level_cache}</prop>
            <prop key="hibernate.cache.region.factory_class">
                org.hibernate.cache.ehcache.SingletonEhCacheRegionFactory
            </prop>

            <prop key="hibernate.ejb.cfgfile">hibernate.cfg.xml</prop>
            <prop key="hibernate.generate_statistics">true</prop>


            <!-- CONNECTION SETTINGS -->
            <prop key="hibernate.connection.driver_class">
                com.mysql.jdbc.Driver
            </prop>
            <prop key="hibernate.connection.url">
                jdbc:mysql://${dbhost}/${dbschema}?zeroDateTimeBehavior=convertToNull&amp;useUnicode=true&amp;characterEncoding=UTF-8
            </prop>
            <prop key="hibernate.connection.username">${dbuser}</prop>
            <prop key="hibernate.connection.password">${dbpass}</prop>

            <!-- CONNECTION POOLING -->
            <prop key="hibernate.connection.provider_class">
                org.hibernate.connection.C3P0ConnectionProvider
            </prop>
            <prop key="hibernate.c3p0.maxPoolSize">${hibernate.c3p0.maxSize}</prop>
            <prop key="hibernate.c3p0.minPoolSize">${hibernate.c3p0.minSize}</prop>
            <prop key="hibernate.c3p0.acquireIncrement">${hibernate.c3p0.acquireIncrement}</prop>
            <prop key="hibernate.c3p0.idleConnectionTestPeriod">${hibernate.c3p0.idleTestPeriod}</prop>
            <prop key="hibernate.c3p0.maxStatements">${hibernate.c3p0.maxStatements}</prop>
            <prop key="hibernate.c3p0.timeout">${hibernate.c3p0.timeout}</prop>

        </props>
    </property>
</bean>

<bean id="jpaAdapter"
    class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter" />

真的
org.hibernate.dialogue.mysqldialogue
${hibernate.cache.use\u query\u cache}
${hibernate.cache.use_second_level_cache}
org.hibernate.cache.ehcache.SingletonEhCacheRegionFactory
hibernate.cfg.xml
真的
com.mysql.jdbc.Driver
jdbc:mysql://${dbhost}/${dbschema}?zeroDateTimeBehavior=convertToNull&;useUnicode=true&;characterEncoding=UTF-8
${dbuser}
${dbpass}
org.hibernate.connection.C3P0ConnectionProvider
${hibernate.c3p0.maxSize}
${hibernate.c3p0.minSize}
${hibernate.c3p0.acquireIncrement}
${hibernate.c3p0.idleTestPeriod}
${hibernate.c3p0.maxStatements}
${hibernate.c3p0.timeout}


假设数据库模式是正确的,假设我在事件中获得了数据库凭据和主机信息,我需要“重新设置”连接池。

如果您要求多个数据库连接。.在hibernate中,可以通过创建多个
hibernate.cfg.file
,这是不合适的

通过遵循这条路线,你可以做到这一点

SessionFactory sf = new Configuration().configure("somename.cfg.xml").buildSessionFactory();
当您的主连接未建立时,您已加载另一个
休眠配置
…否则将不可能。

是一个不错的选择

Xml或注释的用法如下:

<bean id="ds1" class="..c3p0.DataSource">
    ...
</bean>

<bean id="ds2" class="..c3p0.DataSource">
    ...
</bean>

<bean id="dataSource" class="..xxx.RoutingDataSource">
   <property name="targetDataSources">
      <map key-type="java.lang.String">
         <entry key="ds1" value-ref="ds1"/>
         <entry key="ds2" value-ref="ds2"/>             
      </map>
   </property>
   <property name="defaultTargetDataSource" ref="ds1"/>
</bean>



<bean id="sessionFactory"
    class="org.springframework.orm.hibernate3.annotation.AnnotationSessionFactoryBean">
    <property name="dataSource" ref="dataSource" /> 
...
</bean>

cfg.xml不是hibernate.ejb.cfgfile的配置文件吗?它只定义了二级缓存配置?抽象路由数据源将帮助我路由到一个现有的数据源。我们的要求是从现在开始使用不同的数据源,它应该在发生事件时创建。我添加了spring配置文件作为questionRoutingDataSource的一部分,可以动态修改数据源映射。检查AbstractRoutingDataSource API。这太棒了!谢谢。
public class RoutingDataSource extends AbstractRoutingDataSource {
    private static final ThreadLocal<String> holder = new ThreadLocal<String>();

    protected Object determineCurrentLookupKey()
    {
        return holder.get();
    }

    public static void clear(){
        holder.remove();
    }

    public static void setDataSourceKey(String key){
        holder.set(key);
    }

}
try{
    RoutingDataSource.setDataSourceKey("ds1");
    myDao.doXXX();
}finally{
    RoutingDataSource.clear();
}
<beans:bean id="dataSource"
    class="org.springframework.aop.framework.ProxyFactoryBean">
    <beans:property name="targetSource" ref="swappableDataSource" />
</beans:bean>

<beans:bean id="dummyDataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource"
    destroy-method="close" />

<beans:bean name="swappableDataSource"
    class="org.springframework.aop.target.HotSwappableTargetSource">
    <beans:constructor-arg ref="dummyDataSource" />
</beans:bean>
@Autowired
HotSwappableTargetSource swapable;

public void changeDatasource() throws Exception
{
            swapable.swap(createNewSource();

}


ComboPooledDataSource createNewSource() throws Exception {
    ComboPooledDataSource ds2 = new ComboPooledDataSource();
    ds2.setJdbcUrl(url);
    ds2.setDriverClass(driver);
    ds2.setUser(username);
    ds2.setPassword(password);


    return ds2;
}