spring动态加载数据源

9 篇文章 0 订阅
7 篇文章 0 订阅

前段时间有个项目,spring+hibernate 的框架,这个项目是数据库传输相关的,会配置好几个数据库,就考虑能否把数据库配置放在 一个表里,程序启动时加载,这样会减少配置文件,清晰明了。

简介

如果你的工程要操作多个数据库,而且都要集成到spring中,用spring 的配置文件配置是很常见的。配置多个xml然后import到主xml(applicationContext.xml),里面把datasource 和beanfactory ,扫描包等配置好即可,

不过动态加的话,就有所不同了。当然是先 百度/google一下了,发现有不少案例是 多数据源+动态切换,不过这和我们的程序还是有出入的.后来找到一个 动态加bean 的,类似:

DefaultListableBeanFactory dbf = (DefaultListableBeanFactory) appContext.getBeanFactory();
        BeanDefinitionBuilder dataSourceBuider = BeanDefinitionBuilder.genericBeanDefinition(ComboPooledDataSource.class);

有了这个ioc的入口,那就简单些了,至少在定义bean方面是没问题的。

代码

文件一,beans.xml

<?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:aop="http://www.springframework.org/schema/aop"
    xmlns:tx="http://www.springframework.org/schema/tx" xmlns:jdbc="http://www.springframework.org/schema/jdbc"
    xmlns:context="http://www.springframework.org/schema/context"
    xmlns:task="http://www.springframework.org/schema/task" 
    xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.1.xsd
    http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-4.1.xsd
    http://www.springframework.org/schema/jee http://www.springframework.org/schema/jee/spring-jee-4.1.xsd
    http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.1.xsd
    http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-4.1.xsd
    http://www.springframework.org/schema/task http://www.springframework.org/schema/task/spring-task-4.1.xsd">



</beans>

文件二,ThirdImplTest.java (启动spring动态加载数据源)

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Properties;

import javax.sql.DataSource;

import org.apache.log4j.Logger;
import org.junit.Before;
import org.junit.Test;
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
import org.springframework.beans.factory.support.DefaultListableBeanFactory;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import org.springframework.orm.hibernate4.LocalSessionFactoryBean;

import com.mchange.v2.c3p0.ComboPooledDataSource;

public class ThirdImplTest {

    static Logger log = Logger.getLogger(TgdUserServiceThirdImplTest.class);

    TgdUserServiceThirdImpl impl ;

    @Before
    public void beforeS() {
        ConfigurableApplicationContext  appContext = new ClassPathXmlApplicationContext("classpath:beans.xml");
        appContext = (ConfigurableApplicationContext) tooper(appContext);
        impl = (TgdUserServiceThirdImpl)appContext.getBean("tgdUserServiceThirdImpl");

    }

    /**
     * 操作 代码注入
     * @param dbf
     * @param appContext
     */
    private ApplicationContext   tooper(ConfigurableApplicationContext  appContext){

        String driverClass = "com.mysql.jdbc.Driver";
        String jdbcUrl = "jdbc:mysql://192.168.1.1:3306/xxx?createDatabaseIfNotExist=true&useUnicode=true&characterEncoding=utf-8&zeroDateTimeBehavior=convertToNull&transformedBitIsBoolean=true&pinGlobalTxToPhysicalConnection=true&autoReconnect=true&useOldAliasMetadataBehavior=true";
        String user = "root";
        String password = "xxxx";

        DefaultListableBeanFactory dbf = (DefaultListableBeanFactory) appContext.getBeanFactory();
        BeanDefinitionBuilder dataSourceBuider = BeanDefinitionBuilder .genericBeanDefinition(ComboPooledDataSource.class);  
        dataSourceBuider.addPropertyValue("driverClass", driverClass);  
        dataSourceBuider.addPropertyValue("jdbcUrl", jdbcUrl);
        dataSourceBuider.addPropertyValue("user",user);
        dataSourceBuider.addPropertyValue("password",password);
        dataSourceBuider.addPropertyValue("acquireIncrement","5");
        dataSourceBuider.addPropertyValue("initialPoolSize","3");
        dataSourceBuider.addPropertyValue("minPoolSize","3");
        dataSourceBuider.addPropertyValue("maxPoolSize","10");
        dataSourceBuider.addPropertyValue("maxIdleTime","600");
        dataSourceBuider.addPropertyValue("idleConnectionTestPeriod","3600");
        dataSourceBuider.addPropertyValue("maxStatements","100");
        dataSourceBuider.addPropertyValue("numHelperThreads","10");
        dataSourceBuider.addPropertyValue("testConnectionOnCheckout",false);
        dataSourceBuider.addPropertyValue("preferredTestQuery","SELECT 1 FROM DUAL");
        dataSourceBuider.addPropertyValue("breakAfterAcquireFailure",false);
        dataSourceBuider.addPropertyValue("acquireRetryAttempts",30);
        dbf.registerBeanDefinition("third_dataSource", dataSourceBuider.getBeanDefinition());

        // 配置 LocalSessionFactoryBean
        //LocalSessionFactoryBean注册,注册时候在获取结果不再是它本身而是sessionFactory  
        BeanDefinitionBuilder llfb = BeanDefinitionBuilder .genericBeanDefinition(LocalSessionFactoryBean.class);  
        //这里的属性对应配置文件或者LocalSessionFactoryBean源码中的属性来,自己去看看就晓得  
        llfb.addPropertyValue("dataSource", (DataSource)appContext.getBean("third_dataSource"));  
        List<String> packagesToScanList = new ArrayList();
        packagesToScanList.add("com.snm.third");
        llfb.addPropertyValue("packagesToScan", packagesToScanList);

        Properties p = new Properties();
        p.setProperty("hibernate.hbm2ddl.auto","none");
        p.setProperty("hibernate.dialect","org.hibernate.dialect.MySQL5Dialect");
        p.setProperty("hibernate.show_sql","true");
        p.setProperty("hibernate.form_sql","true");
        p.setProperty("hibernate.connection.username",user);
        p.setProperty("hibernate.connection.password",password);
        p.setProperty("hibernate.connection.url",jdbcUrl);
        p.setProperty("hibernate.default_batch_fetch_size","30");
        p.setProperty("hibernate.cache.use_second_level_cache","false");
        p.setProperty("hibernate.current_session_context_class","org.springframework.orm.hibernate4.SpringSessionContext");
//        p.setProperty("hibernate.current_session_context_class","thread");


        llfb.addPropertyValue("hibernateProperties",p);
        dbf.registerBeanDefinition("third_sessionFactory", llfb.getBeanDefinition()); 



//        本来想看看集成spring 事务怎么搞的, 不过搞不定,这几行貌似没什么用
     // construct an appropriate transaction manager 
//        DataSourceTransactionManager txManager = new DataSourceTransactionManager((DataSource)appContext.getBean("third_dataSource"));
//        // configure the AnnotationTransactionAspect to use it; this must be done before executing any transactional methods
//        AnnotationTransactionAspect.aspectOf().setTransactionManager(txManager); 


        AnnotationConfigApplicationContext  annotationConfigApplicationContext = 
                new AnnotationConfigApplicationContext();

        annotationConfigApplicationContext.setParent(appContext);
        annotationConfigApplicationContext.scan("com.xxx.xxx");
        annotationConfigApplicationContext.refresh();
        return annotationConfigApplicationContext;
    }

    @Test
    public void testgetAllList() throws Exception {
        log.info(DJsonUtil.getJsonFromObect(impl.getAllList1(new HashMap(), null)));
    }
}

文件三 TUserServiceThirdImpl

import java.util.List;
import java.util.Map;

import org.hibernate.SQLQuery;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import com.apache.util.Sort;
import com.snm.third.model.equpt.TgdUser;


@Service
public class TUserServiceThirdImpl{

    @Autowired
    private SessionFactory sessionFactory;

    public List getAllList1(Map<String, String> params, Sort sorts) {
        Session session = null;
        List list = null;
        try {
            session = sessionFactory.openSession();
            SQLQuery query = session.createSQLQuery("select * from tuser");
            list = query.list();
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            session.close();
        }
        return list;
    }
}

上面三个文件,即可以使用了.

其它

  • 在web中使用
    在加载sping 时自己创建个类来继承sping的listen,重写
    public void contextInitialized(ServletContextEvent event) 即可
public class SpringListener extends ContextLoaderListener{

    private static ApplicationContext context ;

    public static ApplicationContext getContext(){
        return context;
    }

    @Override
    public void contextInitialized(ServletContextEvent event) {
        System.out.print("init spring================");
        super.contextInitialized(event);
        WebApplicationContext w = WebApplicationContextUtils.getWebApplicationContext(event.getServletContext());
        context = tooper((ConfigurableApplicationContext) w); //这里加载
    }

问题

  • 自动事务问题
    不知道spring的aop怎么配置,即这行不知道怎么配置。
<tx:annotation-driven transaction-manager="transactionManager" />

所以@Transactional 的使用暂时还没有。。如果要多数据源的事务,只能 begin后rollback

  • 数据源的相互引用
    平时使用spring的bean,都是直接@Resource,@Autowire 引进来,但多数据源的相互引用不行,数据源是一个个加载的,如果加A的过程中,有B的Autowire,则会依赖报错 。

  • spring cloud ?
    貌似有spring搭建配置中心 的说法,不过还没了解过.

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值