多数据源切换
来源:互联网 发布:return of the mac 编辑:程序博客网 时间:2024/05/14 10:06
我们以前发布器的做法是用作为方法的一个参数由调用者一直传到访问对象(索引或数据库),虽然这种做法一样可以很快的实现,但是将数据库,索引的选择和业务逻辑混搭在一起的设计在感觉上是比较混乱,并且不利于将来多个城市(频道)的建立,所以选了通过ThreadLocal来实现多数据源的动态切换.
ThreadLocal 是一个依赖于执行线程的存储器,对它就只有简单的一个set和get方法,不同线程之间是相互独立的。简单地讲,就是:这个线程set了一个对象入去,只有这个线程自己可以把它get出来,其它线程是get不出来的。
好了,下面是具体显示的方式
首先定义一个filter,通过filter取得域名,因为我们的域名中带有城市的标志,如广州是http://gz.***.com,上海是http://sh.***.com,通过取得的域名,我们取得城市的表示放进ThreadLocal.set(city);
<!--
Code highlighting produced by Actipro CodeHighlighter (freeware)
http://www.CodeHighlighter.com/
-->public class DataSourceFilter extends HttpServlet implements Filter {
public void doFilter(ServletRequest request, ServletResponse response,
FilterChain filterChain) {
HttpServletRequest req = (HttpServletRequest) request;
String servername = req.getServerName();
SpObserver.putCityByDomain(servername);
filterChain.doFilter(request, response);
}
}
public class SpObserver {
private static ThreadLocal<String> local = new ThreadLocal<String>();
public static void putCityByDomain(String domain) {
String city = publicconfig.getCityMap().get(domain);//拆分domain,获取城市名
local.set(city);
}
public static String getCity() {
String city = (String) local.get();
return city;
}
}
Code highlighting produced by Actipro CodeHighlighter (freeware)
http://www.CodeHighlighter.com/
-->public class DataSourceFilter extends HttpServlet implements Filter {
public void doFilter(ServletRequest request, ServletResponse response,
FilterChain filterChain) {
HttpServletRequest req = (HttpServletRequest) request;
String servername = req.getServerName();
SpObserver.putCityByDomain(servername);
filterChain.doFilter(request, response);
}
}
public class SpObserver {
private static ThreadLocal<String> local = new ThreadLocal<String>();
public static void putCityByDomain(String domain) {
String city = publicconfig.getCityMap().get(domain);//拆分domain,获取城市名
local.set(city);
}
public static String getCity() {
String city = (String) local.get();
return city;
}
}
建立多个与之对应的数据源
<!--
Code highlighting produced by Actipro CodeHighlighter (freeware)
http://www.CodeHighlighter.com/
-->
<bean id="atomDataSource_gz"
class="com.atomikos.jdbc.AtomikosDataSourceBean" init-method="init"
destroy-method="close">
<property name="uniqueResourceName">
<value>mysql/gz</value>
</property>
<property name="xaDataSourceClassName">
<value>com.mysql.jdbc.jdbc2.optional.MysqlXADataSource</value>
</property>
<property name="xaProperties">
<props>
<prop key="URL"><![CDATA[${jdbc_gz.url}]]></prop>
<prop key="user"><![CDATA[${jdbc_gz.username}]]></prop>
<prop key="password"><![CDATA[${jdbc_gz.password}]]></prop>
</props>
</property>
<property name="maxPoolSize">
<value>50</value>
</property>
<property name="minPoolSize">
<value>5</value>
</property>
<property name="loginTimeout">
<value>20</value>
</property>
<property name="testQuery">
<value>SELECT 1</value>
</property>
</bean>
<bean id="atomDataSource_sh"
class="com.atomikos.jdbc.AtomikosDataSourceBean" init-method="init"
destroy-method="close">
<property name="uniqueResourceName">
<value>mysql/sh</value>
</property>
<property name="xaDataSourceClassName">
<value>com.mysql.jdbc.jdbc2.optional.MysqlXADataSource</value>
</property>
<property name="xaProperties">
<props>
<prop key="URL"><![CDATA[${jdbc_sh.url}]]></prop>
<prop key="user"><![CDATA[${jdbc_sh.username}]]></prop>
<prop key="password"><![CDATA[${jdbc_sh.password}]]></prop>
</props>
</property>
<property name="maxPoolSize">
<value>50</value>
</property>
<property name="minPoolSize">
<value>5</value>
</property>
<property name="loginTimeout">
<value>20</value>
</property>
<property name="testQuery">
<value>SELECT 1</value>
</property>
</bean>
<bean id="dataSource" class="com.***.shine.constant.MultiDataSource">
<property name="dataSource" ref="atomDataSource_gz" /> <!-- 默认城市为gz -->
</bean>
Code highlighting produced by Actipro CodeHighlighter (freeware)
http://www.CodeHighlighter.com/
-->
<bean id="atomDataSource_gz"
class="com.atomikos.jdbc.AtomikosDataSourceBean" init-method="init"
destroy-method="close">
<property name="uniqueResourceName">
<value>mysql/gz</value>
</property>
<property name="xaDataSourceClassName">
<value>com.mysql.jdbc.jdbc2.optional.MysqlXADataSource</value>
</property>
<property name="xaProperties">
<props>
<prop key="URL"><![CDATA[${jdbc_gz.url}]]></prop>
<prop key="user"><![CDATA[${jdbc_gz.username}]]></prop>
<prop key="password"><![CDATA[${jdbc_gz.password}]]></prop>
</props>
</property>
<property name="maxPoolSize">
<value>50</value>
</property>
<property name="minPoolSize">
<value>5</value>
</property>
<property name="loginTimeout">
<value>20</value>
</property>
<property name="testQuery">
<value>SELECT 1</value>
</property>
</bean>
<bean id="atomDataSource_sh"
class="com.atomikos.jdbc.AtomikosDataSourceBean" init-method="init"
destroy-method="close">
<property name="uniqueResourceName">
<value>mysql/sh</value>
</property>
<property name="xaDataSourceClassName">
<value>com.mysql.jdbc.jdbc2.optional.MysqlXADataSource</value>
</property>
<property name="xaProperties">
<props>
<prop key="URL"><![CDATA[${jdbc_sh.url}]]></prop>
<prop key="user"><![CDATA[${jdbc_sh.username}]]></prop>
<prop key="password"><![CDATA[${jdbc_sh.password}]]></prop>
</props>
</property>
<property name="maxPoolSize">
<value>50</value>
</property>
<property name="minPoolSize">
<value>5</value>
</property>
<property name="loginTimeout">
<value>20</value>
</property>
<property name="testQuery">
<value>SELECT 1</value>
</property>
</bean>
<bean id="dataSource" class="com.***.shine.constant.MultiDataSource">
<property name="dataSource" ref="atomDataSource_gz" /> <!-- 默认城市为gz -->
</bean>
<!--
Code highlighting produced by Actipro CodeHighlighter (freeware)
http://www.CodeHighlighter.com/
-->
public class MultiDataSource extends AtomikosDataSourceBean implements ApplicationContextAware {
private ApplicationContext applicationContext = null;
private DataSource dataSource = null;
public Connection getConnection() throws SQLException {
return getDataSource().getConnection();
}
public Connection getConnection(String arg0, String arg1)
throws SQLException {
return getDataSource().getConnection(arg0, arg1);
}
..
//通过适配者的设计模式动态的切换实现类,这样就实现了在DataSourceBean中,我们是要注入atomDataSource_gz还是atomDataSource_sh
public DataSource getDataSource(String dataSourceName) {
try{
if(dataSourceName==null||dataSourceName.equals("")){
return this.dataSource;
}
return (DataSource)this.applicationContext.getBean(dataSourceName);
}catch(NoSuchBeanDefinitionException ex){
throw new DaoException("There is not the dataSource <name:"+dataSourceName+"> in the applicationContext!");
}
}
public void setDataSource(DataSource dataSource) {
this.dataSource = dataSource;
}
//主要是下面这一段,通过SpObserver.getCity() 获取相应的城市(频道)名字
public DataSource getDataSource(){
String city = SpObserver.getCity();
if(city == null || city.equals("") || city.equals("null"))
city = "gz";
return getDataSource("atomDataSource_"+city);
}
...
}
Code highlighting produced by Actipro CodeHighlighter (freeware)
http://www.CodeHighlighter.com/
-->
public class MultiDataSource extends AtomikosDataSourceBean implements ApplicationContextAware {
private ApplicationContext applicationContext = null;
private DataSource dataSource = null;
public Connection getConnection() throws SQLException {
return getDataSource().getConnection();
}
public Connection getConnection(String arg0, String arg1)
throws SQLException {
return getDataSource().getConnection(arg0, arg1);
}
..
//通过适配者的设计模式动态的切换实现类,这样就实现了在DataSourceBean中,我们是要注入atomDataSource_gz还是atomDataSource_sh
public DataSource getDataSource(String dataSourceName) {
try{
if(dataSourceName==null||dataSourceName.equals("")){
return this.dataSource;
}
return (DataSource)this.applicationContext.getBean(dataSourceName);
}catch(NoSuchBeanDefinitionException ex){
throw new DaoException("There is not the dataSource <name:"+dataSourceName+"> in the applicationContext!");
}
}
public void setDataSource(DataSource dataSource) {
this.dataSource = dataSource;
}
//主要是下面这一段,通过SpObserver.getCity() 获取相应的城市(频道)名字
public DataSource getDataSource(){
String city = SpObserver.getCity();
if(city == null || city.equals("") || city.equals("null"))
city = "gz";
return getDataSource("atomDataSource_"+city);
}
...
}
这样在各个层中的实现我们就不需去关注究竟是哪个城市的接口,因为每个请求都附带了ThreadLocal的相应信息
<!-- 配置多个数据源,防止主数据库挂掉,应急数据源启用-->
- public class MultiDataSource extends AbstractRoutingDataSource {
- private static final Logger logger = Logger.getLogger(MultiDataSource.class);
- private Object[] targetDataSourcesKeys = null;
- private static final ThreadLocal<Object> contextHolder = new ThreadLocal<Object>();
- public static void setCurrentLookupKeyIndex(Integer currentLookupKeyIndex) {
- Assert.notNull(currentLookupKeyIndex,
- "current LookupKey cannot be null");
- contextHolder.set(currentLookupKeyIndex);
- }
- public static Integer getCurrentLookupKeyIndex() {
- Integer i = (Integer) contextHolder.get();
- if (i == null) {
- setCurrentLookupKeyIndex(0);
- return new Integer(0);
- } else {
- return i;
- }
- }
- public static void clearCurrentLookupKeyIndex() {
- contextHolder.remove();
- }
- protected Object determineCurrentLookupKey() {
- return targetDataSourcesKeys[getCurrentLookupKeyIndex().intValue()];
- }
- public Connection getConnection() throws SQLException{
- setCurrentLookupKeyIndex(0);
- for(int i=0 ; i<targetDataSourcesKeys.length ;){
- try{
- Connection conn = determineTargetDataSource().getConnection();
- logger,info("now datasourse is ***********########"+targetDataSourcesKeys[i]);
- //获取连接成功
- return conn;
- }catch(Exception e){
- //获取连接失败
- setCurrentLookupKeyIndex(++i);
- }
- }
- return determineTargetDataSource().getConnection();
- }
- public void setDataSourceLookup(DataSourceLookup dataSourceLookup) {
- super.setDataSourceLookup(dataSourceLookup);
- }
- public void setDefaultTargetDataSource(Object defaultTargetDataSource) {
- super.setDefaultTargetDataSource(defaultTargetDataSource);
- }
- public void setTargetDataSources(Map targetDataSources) {
- this.targetDataSourcesKeys = targetDataSources.keySet().toArray();
- setCurrentLookupKeyIndex(0);
- super.setTargetDataSources(targetDataSources);
- }
- }
Spring配置
- <bean id="myds1" class="org.springframework.jndi.JndiObjectFactoryBean" destroy-method="close">
- <property name="jndiName">
- <value>myds1</value>
- </property>
- </bean>
- <bean id="myds2" class="org.springframework.jndi.JndiObjectFactoryBean" destroy-method="close">
- <property name="jndiName">
- <value>myds2</value>
- </property>
- </bean>
- <bean id="myds3" class="org.springframework.jndi.JndiObjectFactoryBean" destroy-method="close">
- <property name="jndiName">
- <value>myds3</value>
- </property>
- </bean>
- <util:map id="ourDs">
- <entry key="ds1" value-ref="myds1" />
- <entry key="ds2" value-ref="myds2" />
- <entry key="ds3" value-ref="myds3" />
- </util:map>
- <bean id="dataSourceLookup" class="org.springframework.jdbc.datasource.lookup.MapDataSourceLookup">
- <constructor-arg>
- <ref bean="ourDs" />
- </constructor-arg>
- </bean>
- <bean id="myDs" class="com.huawei.nser.cache.MultiDataSource">
- <property name="defaultTargetDataSource" ref="myds1" />
- <property name="targetDataSources" ref="ourDs" />
- <property name="dataSourceLookup" ref="dataSourceLookup" />
- </bean>
- 多数据源切换
- spring 多数据源切换
- Java 多数据源切换
- Spring多数据源切换
- proxool 多数据源动态切换
- Mybatis+Proxool+Spring多数据源切换
- Spring多数据源的动态切换
- Spring动态切换多数据源解决方案
- IBATIS下多数据源切换
- hibernate4+spring实现多数据源切换
- Spring mvc多数据源切换
- Spring多数据源的动态切换
- Spring实现多数据源动态切换
- koala 多数据源动态切换
- Spring HIbernate 多数据源切换
- spring+mybatis多数据源切换
- Spring动态切换多数据源解决方案
- IBATIS下多数据源切换
- ERROR 010096: There is no Spatial Analyst license currently available or enabled.
- js的数组操作 splice
- C++ primer plus 第7章 函数——C++的编程模块
- Jacobi迭代和Gauss迭代 c语言实现
- C++ primer plus 第8章 函数探幽
- 多数据源切换
- HTML页面跳转方法及代码
- php环境搭建
- C语言在嵌入式系统的不足
- 拉格朗日插值法 C语言实现
- SqlTransaction 对事物的处理
- OpenMP: 循环结构的并行
- js表单验证控制代码大全
- 我们的保险哪去了 美国的什么样子