锁定老帖子 主题:动态切换多数据源
该帖已经被评为良好帖
|
|
---|---|
作者 | 正文 |
发表时间:2006-07-22
一个实现,运行通过,不知道是否有其他问题。
<?xml version="1.0"?> <!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN//EN" "http://wwww.springframework.org/dtd/spring-beans.dtd"> <beans> <bean id="placeholderConfig" class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer"> <property name="location"> <value>springwork/core/aop/targetsource/init.properties</value> </property> </bean> <bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource"> <property name="driverClassName"> <value>${datasource.driverClassName}</value> </property> <property name="url"> <value>${datasource.url}</value> </property> <property name="username"> <value>${datasource.username}</value> </property> <property name="password"> <value>${datasource.password}</value> </property> </bean> <bean id="dataSource1" class="org.apache.commons.dbcp.BasicDataSource"> <property name="driverClassName"> <value>${datasource.driverClassName}</value> </property> <property name="url"> <value>${datasource.url1}</value> </property> <property name="username"> <value>${datasource.username}</value> </property> <property name="password"> <value>${datasource.password}</value> </property> </bean> <bean id="swappableDataSource" class="org.springframework.aop.target.HotSwappableTargetSource"> <constructor-arg> <ref local="dataSource"/> </constructor-arg> </bean> <bean id="swappable" class="org.springframework.aop.framework.ProxyFactoryBean"> <property name="targetSource"> <ref local="swappableDataSource"/> </property> </bean> <bean id="sessionFactory" class="org.springframework.orm.hibernate3.LocalSessionFactoryBean"> <property name="dataSource"> <ref local="swappable"/> </property> <property name="mappingResources"> <list> <value>springwork/core/aop/targetsource/Cat.hbm.xml</value> </list> </property> <property name="hibernateProperties"> <props> <prop key="hibernate.dialect"> ${hibernate.dialect} </prop> <prop key="hibernate.show_sql">true</prop> <prop key="hibernate.generate_statistics">true</prop> <prop key="hibernate.cache.provider_class"> net.sf.ehcache.hibernate.SingletonEhCacheProvider</prop> </props> </property> </bean> <bean id="catDAO" class="springwork.core.aop.targetsource.CatDAO"> <property name="sessionFactory"> <ref local="sessionFactory"/> </property> </bean> <bean id="transactionManager" class="org.springframework.orm.hibernate3.HibernateTransactionManager"> <property name="sessionFactory"> <ref local="sessionFactory"/> </property> </bean> <!-- <bean id="transactionManager" class="org.springframework.transaction.jta.JtaTransactionManager"> </bean> --> <!-- Transaction Interceptor --> <bean id="transactionInterceptor" class="org.springframework.transaction.interceptor.TransactionInterceptor" dependency-check="none"> <property name="transactionManager"> <ref bean="transactionManager"/> </property> <property name="transactionAttributes"> <props> <prop key="*">PROPAGATION_REQUIRED,readOnly</prop> <prop key="save*">PROPAGATION_REQUIRED</prop> <prop key="get*">PROPAGATION_REQUIRED</prop> </props> </property> </bean> <bean id="autoProxyCreator" class="org.springframework.aop.framework.autoproxy.BeanNameAutoProxyCreator" dependency-check="none"> <property name="proxyTargetClass"> <value>true</value> </property> <property name="interceptorNames"> <list> <value>transactionInterceptor</value> </list> </property> <property name="beanNames"> <list> <value>catDAO</value> </list> </property> </bean> </beans> public void testWithTwoDataSource(); { Cat cat=new Cat("mimi");; catDAO.save(cat);; Assert.assertNotNull(cat.getId(););; Cat cat2=new Cat("xixi");; HotSwappableTargetSource swapper=(HotSwappableTargetSource); application.getBean("swappableDataSource");; DataSource newDataSource=(DataSource);application.getBean("dataSource1");; swapper.swap(newDataSource);; catDAO.save(cat2);; Assert.assertNotNull(cat2.getId(););; } btw:可以配置多个SessionFactory,使用JTA处理你的事务问题, 如果你需要跨数据库支持事务的话这样是必须的。 |
|
返回顶楼 | |
发表时间:2006-07-22
TO: knight6892
谢谢你的回覆,我觉得你的方法和代码应该是目前动态数据源在spring中最好的实现了. 不过不知道数据源在切换中性能是否有影响,本来按照我的想法,sessionFactory是有多个,然后动态切换sessionFactory.但也许不可行,目前我使用自己的方法测试过查询数据,没有测试有关事务方面的操作.估计是不行. 接下来使用你的方法,进行测试,稍后会继续发贴. |
|
返回顶楼 | |
发表时间:2006-07-24
1。在只有一个数据源的时候,使用 spring + hibernate 的情况下,通常在程序中是存在一个 spring 的 beanfactory 的,而且通常这个 beanfactory 还是由 spring 提供的 servlet 自动创建的。通常会在 web 层的 action 里面通过这个 beanfactory 获得 BO,然后调用 BO 来实现相关的功能。
2。在有多个数据源的时候,需要为每个数据源生成一个 beanfactory 。这个目前可能无法通过 spring 提供的 servlet 来自动实现,需要自己手工来操作。这些 beanfactory 使用同样的 spring xml 配置文件,但是使用不同的数据库配置文件。手工操作的代码类似: ClassPathXmlApplicationContext factory = new ClassPathXmlApplicationContext( contextFile, false );; Properties props = new Properties();; props.load( new FileInputStream( propFile ); );; PropertyPlaceholderConfigurer configurer = new PropertyPlaceholderConfigurer();; configurer.setProperties( props );; factory.addBeanFactoryPostProcessor( configurer );; factory.refresh();; 对应每一个数据源,在程序启动的时候生成一个 factory ,然后可以为每个 factory 和数据源标识对应起来保存在 hashmap 之类的列表中,以方便后面使用。 3。web 层的 action 不能再在 spring 的配置文件中出现了。在 web 层的 action 里面都实现一个 BeanFactoryAware 的 Interface 。 public interface BeanFactoryAware { public void setBeanFactory( BeanFactory factory );; } 在这个 setBeanFactory 函数里面,每个 action 主动从 beanfactory 里面获得自己想要的 BO 。 用户选择的数据源信息可以记录在 session 里面,然后针对 BeanFactoryAware 接口写一个 interceptor ,从 session 里面取得用户的设置,再根据用户的设置取得对应的 BeanFactory ,然后调用 action 的 setBeanFactory 函数。 4。这几个 beanfactory 是相互独立的,不会相互干扰。假设 数据源 A ---》 bfA 数据源 B ---》 bfB 从 bfA 中得到的所有对象都是和数据源 A 相关的,从 bfB 中得到的所有对象都是和数据源 B 相关的。 5。这种做法的缺点是在 action 中,BO 无法再使用 IoC 的方式来注入,而是要自己主动注入。当然,在 setBeanFactory 函数里面,也可以显式地调用 beanfactory 和 this 来做到 IoC 。 补充:写完之后,忽然想到,其实可以在 interceptor 里面来做 IoC 的操作,这个 BeanFactoryAware 可以根本不需要有任何方法,只是作为一个标识接口就可以了。具体还没试过,之前做过多数据源的项目,用的是上面的做法。 |
|
返回顶楼 | |
发表时间:2006-11-14
knight6892 写道 一个实现,运行通过,不知道是否有其他问题。
<?xml version="1.0"?> <!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN//EN" "http://wwww.springframework.org/dtd/spring-beans.dtd"> <beans> <bean id="placeholderConfig" class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer"> <property name="location"> <value>springwork/core/aop/targetsource/init.properties</value> </property> </bean> <bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource"> <property name="driverClassName"> <value>${datasource.driverClassName}</value> </property> <property name="url"> <value>${datasource.url}</value> </property> <property name="username"> <value>${datasource.username}</value> </property> <property name="password"> <value>${datasource.password}</value> </property> </bean> <bean id="dataSource1" class="org.apache.commons.dbcp.BasicDataSource"> <property name="driverClassName"> <value>${datasource.driverClassName}</value> </property> <property name="url"> <value>${datasource.url1}</value> </property> <property name="username"> <value>${datasource.username}</value> </property> <property name="password"> <value>${datasource.password}</value> </property> </bean> <bean id="swappableDataSource" class="org.springframework.aop.target.HotSwappableTargetSource"> <constructor-arg> <ref local="dataSource"/> </constructor-arg> </bean> <bean id="swappable" class="org.springframework.aop.framework.ProxyFactoryBean"> <property name="targetSource"> <ref local="swappableDataSource"/> </property> </bean> <bean id="sessionFactory" class="org.springframework.orm.hibernate3.LocalSessionFactoryBean"> <property name="dataSource"> <ref local="swappable"/> </property> <property name="mappingResources"> <list> <value>springwork/core/aop/targetsource/Cat.hbm.xml</value> </list> </property> <property name="hibernateProperties"> <props> <prop key="hibernate.dialect"> ${hibernate.dialect} </prop> <prop key="hibernate.show_sql">true</prop> <prop key="hibernate.generate_statistics">true</prop> <prop key="hibernate.cache.provider_class"> net.sf.ehcache.hibernate.SingletonEhCacheProvider</prop> </props> </property> </bean> <bean id="catDAO" class="springwork.core.aop.targetsource.CatDAO"> <property name="sessionFactory"> <ref local="sessionFactory"/> </property> </bean> <bean id="transactionManager" class="org.springframework.orm.hibernate3.HibernateTransactionManager"> <property name="sessionFactory"> <ref local="sessionFactory"/> </property> </bean> <!-- <bean id="transactionManager" class="org.springframework.transaction.jta.JtaTransactionManager"> </bean> --> <!-- Transaction Interceptor --> <bean id="transactionInterceptor" class="org.springframework.transaction.interceptor.TransactionInterceptor" dependency-check="none"> <property name="transactionManager"> <ref bean="transactionManager"/> </property> <property name="transactionAttributes"> <props> <prop key="*">PROPAGATION_REQUIRED,readOnly</prop> <prop key="save*">PROPAGATION_REQUIRED</prop> <prop key="get*">PROPAGATION_REQUIRED</prop> </props> </property> </bean> <bean id="autoProxyCreator" class="org.springframework.aop.framework.autoproxy.BeanNameAutoProxyCreator" dependency-check="none"> <property name="proxyTargetClass"> <value>true</value> </property> <property name="interceptorNames"> <list> <value>transactionInterceptor</value> </list> </property> <property name="beanNames"> <list> <value>catDAO</value> </list> </property> </bean> </beans> public void testWithTwoDataSource() { Cat cat=new Cat("mimi"); catDAO.save(cat); Assert.assertNotNull(cat.getId()); Cat cat2=new Cat("xixi"); HotSwappableTargetSource swapper=(HotSwappableTargetSource) application.getBean("swappableDataSource"); DataSource newDataSource=(DataSource)application.getBean("dataSource1"); swapper.swap(newDataSource); catDAO.save(cat2); Assert.assertNotNull(cat2.getId()); } btw:可以配置多个SessionFactory,使用JTA处理你的事务问题, 如果你需要跨数据库支持事务的话这样是必须的。 数据源用JDNI的话,就不行 |
|
返回顶楼 | |
发表时间:2006-11-16
hibernate-Statistics + MX4J + Spring + JNDI
And you just do nothing for your requirement |
|
返回顶楼 | |
发表时间:2006-12-07
To knight6892: 请问你的例子中使用同一个SessionFacotry,是否存在二级缓存的问题?
|
|
返回顶楼 | |
发表时间:2006-12-07
ben_nb 写道 knight6892 写道 一个实现,运行通过,不知道是否有其他问题。
<?xml version="1.0"?> <!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN//EN" "http://wwww.springframework.org/dtd/spring-beans.dtd"> <beans> <bean id="placeholderConfig" class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer"> <property name="location"> <value>springwork/core/aop/targetsource/init.properties</value> </property> </bean> <bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource"> <property name="driverClassName"> <value>${datasource.driverClassName}</value> </property> <property name="url"> <value>${datasource.url}</value> </property> <property name="username"> <value>${datasource.username}</value> </property> <property name="password"> <value>${datasource.password}</value> </property> </bean> <bean id="dataSource1" class="org.apache.commons.dbcp.BasicDataSource"> <property name="driverClassName"> <value>${datasource.driverClassName}</value> </property> <property name="url"> <value>${datasource.url1}</value> </property> <property name="username"> <value>${datasource.username}</value> </property> <property name="password"> <value>${datasource.password}</value> </property> </bean> <bean id="swappableDataSource" class="org.springframework.aop.target.HotSwappableTargetSource"> <constructor-arg> <ref local="dataSource"/> </constructor-arg> </bean> <bean id="swappable" class="org.springframework.aop.framework.ProxyFactoryBean"> <property name="targetSource"> <ref local="swappableDataSource"/> </property> </bean> <bean id="sessionFactory" class="org.springframework.orm.hibernate3.LocalSessionFactoryBean"> <property name="dataSource"> <ref local="swappable"/> </property> <property name="mappingResources"> <list> <value>springwork/core/aop/targetsource/Cat.hbm.xml</value> </list> </property> <property name="hibernateProperties"> <props> <prop key="hibernate.dialect"> ${hibernate.dialect} </prop> <prop key="hibernate.show_sql">true</prop> <prop key="hibernate.generate_statistics">true</prop> <prop key="hibernate.cache.provider_class"> net.sf.ehcache.hibernate.SingletonEhCacheProvider</prop> </props> </property> </bean> <bean id="catDAO" class="springwork.core.aop.targetsource.CatDAO"> <property name="sessionFactory"> <ref local="sessionFactory"/> </property> </bean> <bean id="transactionManager" class="org.springframework.orm.hibernate3.HibernateTransactionManager"> <property name="sessionFactory"> <ref local="sessionFactory"/> </property> </bean> <!-- <bean id="transactionManager" class="org.springframework.transaction.jta.JtaTransactionManager"> </bean> --> <!-- Transaction Interceptor --> <bean id="transactionInterceptor" class="org.springframework.transaction.interceptor.TransactionInterceptor" dependency-check="none"> <property name="transactionManager"> <ref bean="transactionManager"/> </property> <property name="transactionAttributes"> <props> <prop key="*">PROPAGATION_REQUIRED,readOnly</prop> <prop key="save*">PROPAGATION_REQUIRED</prop> <prop key="get*">PROPAGATION_REQUIRED</prop> </props> </property> </bean> <bean id="autoProxyCreator" class="org.springframework.aop.framework.autoproxy.BeanNameAutoProxyCreator" dependency-check="none"> <property name="proxyTargetClass"> <value>true</value> </property> <property name="interceptorNames"> <list> <value>transactionInterceptor</value> </list> </property> <property name="beanNames"> <list> <value>catDAO</value> </list> </property> </bean> </beans> public void testWithTwoDataSource() { Cat cat=new Cat("mimi"); catDAO.save(cat); Assert.assertNotNull(cat.getId()); Cat cat2=new Cat("xixi"); HotSwappableTargetSource swapper=(HotSwappableTargetSource) application.getBean("swappableDataSource"); DataSource newDataSource=(DataSource)application.getBean("dataSource1"); swapper.swap(newDataSource); catDAO.save(cat2); Assert.assertNotNull(cat2.getId()); } btw:可以配置多个SessionFactory,使用JTA处理你的事务问题, 如果你需要跨数据库支持事务的话这样是必须的。 数据源用JDNI的话,就不行 可以的,但要强制声明代理接口为 DataSource. |
|
返回顶楼 | |
发表时间:2007-03-10
还是多数据源的问题
关注这个网站很久了,这里面高人不少。小弟最近碰到个问题,搞了好久也搞不好,所以来请教这里的大侠们。 现在有个网站新闻系统,有4种语言来发布,中、日、韩、英。于是我在后台发布新闻信息的时候,把不同的语言发布到4个数据库里,这4个数据是完全一样的,只是各自记录不同的语言的新闻。 现在的问题是,我需要让来自不同国家的人能同时访问这个网站而互相没有干扰,来自中国的用户,使用的是中文的数据,来自日本的用户,是使用的日文的数据库,也就是说,不同的用户使用自己不同的数据源。 我看到这里已经有人讨论过这样类似的问题,但还是没搞太明白怎么做,主要是不知道如何把不同的数据源放到不同的sessionfacory里,然后让DAO使用使用这些不同的sessionfactory?? 我的网站是采用的hibernate+spring,applicationcontext文件配置如下: <beans> <!-- Choose the dialect that matches your "dataSource" definition --> <bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource"> <property name="driverClassName"> <value>net.sourceforge.jtds.jdbc.Driver</value> </property> <property name="url"> <value>jdbc:jtds:sqlserver://localhost:1433;SelectMethod=cursor;DatabaseName=NPO</value> </property> <property name="username"> <value>sa</value> </property> <property name="password"> <value>npo1234</value> </property> <property name="maxActive"> <value>100</value> </property> <property name="maxIdle"> <value>10</value> </property> <property name="maxWait"> <value>120000</value> </property> <property name="defaultAutoCommit"> <value>true</value> </property> </bean> <bean id="dataSourceko" class="org.apache.commons.dbcp.BasicDataSource"> <property name="driverClassName"> <value>net.sourceforge.jtds.jdbc.Driver</value> </property> <property name="url"> <value>jdbc:jtds:sqlserver://localhost:1433;SelectMethod=cursor;DatabaseName=NPOKR</value> </property> <property name="username"> <value>sa</value> </property> <property name="password"> <value>npo1234</value> </property> <property name="maxActive"> <value>100</value> </property> <property name="maxIdle"> <value>10</value> </property> <property name="maxWait"> <value>120000</value> </property> <property name="defaultAutoCommit"> <value>true</value> </property> </bean> <bean id="dataSourcejp" class="org.apache.commons.dbcp.BasicDataSource"> <property name="driverClassName"> <value>net.sourceforge.jtds.jdbc.Driver</value> </property> <property name="url"> <value>jdbc:jtds:sqlserver://localhost:1433;SelectMethod=cursor;DatabaseName=NPOJP</value> </property> <property name="username"> <value>sa</value> </property> <property name="password"> <value>npo1234</value> </property> <property name="maxActive"> <value>100</value> </property> <property name="maxIdle"> <value>10</value> </property> <property name="maxWait"> <value>120000</value> </property> <property name="defaultAutoCommit"> <value>true</value> </property> </bean> <bean id="dataSourceen" class="org.apache.commons.dbcp.BasicDataSource"> <property name="driverClassName"> <value>net.sourceforge.jtds.jdbc.Driver</value> </property> <property name="url"> <value>jdbc:jtds:sqlserver://localhost:1433;SelectMethod=cursor;DatabaseName=NPOEN</value> </property> <property name="username"> <value>sa</value> </property> <property name="password"> <value>npo1234</value> </property> <property name="maxActive"> <value>100</value> </property> <property name="maxIdle"> <value>10</value> </property> <property name="maxWait"> <value>120000</value> </property> <property name="defaultAutoCommit"> <value>true</value> </property> </bean> <bean id="swappableDataSource" class="org.springframework.aop.target.HotSwappableTargetSource"> <constructor-arg> <ref local="dataSource"/> </constructor-arg> </bean> <bean id="swappable" class="org.springframework.aop.framework.ProxyFactoryBean"> <property name="targetSource"> <ref local="swappableDataSource"/> </property> </bean> <bean id="mySessionFactory" class="org.springframework.orm.hibernate.LocalSessionFactoryBean"> <property name="dataSource"><ref local="swappable"/></property> <property name="mappingResources"> <list> <value>jaoso/framework/domain/Role.hbm.xml</value> <value>jaoso/framework/domain/Right.hbm.xml</value> <value>jaoso/framework/domain/Account.hbm.xml</value> <value>jaoso/framework/domain/Person.hbm.xml</value> <value>jaoso/news/domain/Catalog.hbm.xml</value> <value>jaoso/news/domain/Article.hbm.xml</value> <value>jaoso/news/domain/Adv.hbm.xml</value> <value>jaoso/news/domain/Critic.hbm.xml</value> <value>jaoso/guestbook/domain/GbCatalog.hbm.xml</value> <value>jaoso/guestbook/domain/Message.hbm.xml</value> <value>jaoso/count/domain/Count.hbm.xml</value> </list> </property> </bean> <!-- Transaction manager for a single Hibernate SessionFactory (alternative to JTA) --> <bean id="myTransactionManager" class="org.springframework.orm.hibernate.HibernateTransactionManager"> <property name="sessionFactory"><ref local="mySessionFactory"/></property> </bean> <!-- ************************** DAO SETTING *********************************--> <!-- DAO object: Hibernate implementation --> <bean id="baseDAO" class="jaoso.framework.dao.hibernate.BaseDAOImpl"> <property name="sessionFactory"><ref local="mySessionFactory"/></property> </bean> <!-- ************************** Persistent Manager SETTING ******************--> <bean id="persistentManager" class="jaoso.framework.dao.hibernate.PersistentManagerImpl"> <property name="baseDAO"><ref local="baseDAO"/></property> </bean> <!-- ************************** Query Manager SETTING ***********************--> <bean id="queryManager" class="jaoso.framework.dao.hibernate.QueryManagerImpl"> <property name="baseDAO"><ref local="baseDAO"/></property> </bean> </beans> |
|
返回顶楼 | |
发表时间:2007-03-10
另外有个globe.java文件,加载配置信息:
*/ private static void init() { String path = Global.class.getResource("/spring/applicationContext.xml") .getPath(); path = path.substring(1, path.length()); File file = new File(path); File dir = file.getParentFile(); String[] files = dir.list(); for (int i = 0, n = files.length; i < n; i++) { files[i] = "/spring/" + files[i]; } log.info("Sping starting*******************"); context = new ClassPathXmlApplicationContext(files); log.info("Sping start success*******************"); } |
|
返回顶楼 | |
发表时间:2007-03-11
spring2.0.1提供了Dynamic DataSource Routing,http://blog.interface21.com/main/2007/01/23/dynamic-datasource-routing/
|
|
返回顶楼 | |