标签:
在spring 2.0.1中引入了AbstractRoutingDataSource, 该类充当了DataSource的路由中介, 能有在运行时, 根据某种key值来动态切换到真正的DataSource上。
Spring动态配置多数据源,即在大型应用中对数据进行切分,并且采用多个数据库实例进行管理,这样可以有效提高系统的水平伸缩性。而这样的方案就会不同于常见的单一数据实例的方案,这就要程序在运行时根据当时的请求及系统状态来动态的决定将数据存储在哪个数据库实例中,以及从哪个数据库提取数据。
Spring对于多数据源,以数据库表为参照,大体上可以分成两大类情况:
一是,表级上的跨数据库。即,对于不同的数据库却有相同的表(表名和表结构完全相同)。
二是,非表级上的跨数据库。即,多个数据源不存在相同的表。
Spring2.x的版本中采用Proxy模式,就是我们在方案中实现一个虚拟的数据源,并且用它来封装数据源选择逻辑,这样就可以有效地将数据源选择逻辑从Client中分离出来。Client提供选择所需的上下文(因为这是Client所知道的),由虚拟的DataSource根据Client提供的上下文来实现数据源的选择。
具体的实现就是,虚拟的DataSource仅需继承AbstractRoutingDataSource实现determineCurrentLookupKey()在其中封装数据源的选择逻辑。
<?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:context="http://www.springframework.org/schema/context"
xmlns:tx="http://www.springframework.org/schema/tx" xmlns:jpa="http://www.springframework.org/schema/data/jpa"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd
http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-2.5.xsd http://www.springframework.org/schema/data/jpa http://www.springframework.org/schema/data/jpa/spring-jpa-1.0.xsd">
<!-- 只有一个数据为时,只需要配置一个bean:dataSource -->
<bean id="dataSource_default" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close">
<property name="driverClassName"><value>com.mysql.jdbc.Driver</value></property>
<property name="url"><value>jdbc:mysql://</value></property>
<property name="username"><value></value></property>
<property name="password"><value></value></property>
<property name="initialSize"><value>2</value></property>
<property name="maxActive"><value>2</value></property>
<property name="minIdle"><value>2</value></property>
<property name="maxIdle"><value>2</value></property>
<property name="maxWait"><value>10000</value></property>
<property name= "testWhileIdle" ><value>true</value></property>
<property name= "testOnBorrow" ><value>true</value></property>
<property name= "testOnReturn" ><value>true</value></property>
<property name= "validationQuery" ><value>select 1 from dual</value></property>
<property name= "timeBetweenEvictionRunsMillis" ><value>30000</value></property>
<property name= "numTestsPerEvictionRun" ><value>32</value></property>
<property name="minEvictableIdleTimeMillis"><value>1800000</value></property>
<property name="removeAbandoned" ><value>true</value></property>
<property name="removeAbandonedTimeout"><value>180</value></property>
</bean>
<bean id="tfj" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close">
<property name="driverClassName"><value>com.mysql.jdbc.Driver</value></property>
<property name="url"><value>jdbc:mysql://</value></property>
<property name="username"><value></value></property>
<property name="password"><value></value></property>
<property name="initialSize"><value>2</value></property>
<property name="maxActive"><value>2</value></property>
<property name="minIdle"><value>2</value></property>
<property name="maxIdle"><value>2</value></property>
<property name="maxWait"><value>10000</value></property>
<property name= "testWhileIdle" ><value>true</value></property>
<property name= "testOnBorrow" ><value>true</value></property>
<property name= "testOnReturn" ><value>true</value></property>
<property name= "validationQuery" ><value>select 1 from dual</value></property>
<property name= "timeBetweenEvictionRunsMillis" ><value>30000</value></property>
<property name= "numTestsPerEvictionRun" ><value>32</value></property>
<property name="minEvictableIdleTimeMillis"><value>1800000</value></property>
<property name="removeAbandoned" ><value>true</value></property>
<property name="removeAbandonedTimeout"><value>180</value></property>
</bean>
<bean id="dataSource" class="">
<property name="targetDataSources">
<map key-type="java.lang.String">
<entry value-ref="dataSource_default" key="default"/>
</map>
</property>
<property name="defaultTargetDataSource" ref="dataSource_default">
</property>
</bean>
//重要的类,他里面存的是动态数据配置文件
<bean id="dcCreateDataSourceBean" class="">
<property name="jdbcTemplate" ref="jdbcTemplate"></property>
<property name="dynamicDataSource" ref="dataSource"></property>
</bean>
<bean id="jdbcTemplate"
class="org.springframework.jdbc.core.JdbcTemplate">
<property name="dataSource" ref="dataSource" />
</bean>
<!-- 用于异步队列更新数据库 -->
<bean id="partitionDBMapping" class="java.util.concurrent.ConcurrentHashMap">
<constructor-arg>
<map>
<entry value="default"
key="databaseGroup" />
</map>
</constructor-arg>
</bean>
</beans>
下面是copy别人的
1
2
3
4
5
6
7
8
9
10
11
12
13
14
|
public void afterPropertiesSet()
{ if ( this .targetDataSources
== null )
{ throw new IllegalArgumentException( "Property
‘targetDataSources‘ is required" ); } this .resolvedDataSources
= new HashMap<Object,
DataSource>( this .targetDataSources.size()); for (Map.Entry
entry : this .targetDataSources.entrySet())
{ Object
lookupKey = resolveSpecifiedLookupKey(entry.getKey()); DataSource
dataSource = resolveSpecifiedDataSource(entry.getValue()); this .resolvedDataSources.put(lookupKey,
dataSource); } if ( this .defaultTargetDataSource
!= null )
{ this .resolvedDefaultDataSource
= resolveSpecifiedDataSource( this .defaultTargetDataSource); } } |
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
|
//查找当前用户上下文变量中设置的数据源. @Override protected Object
determineCurrentLookupKey() { DataSourceType
dataSourceType= DataSourceContextHolder.getDataSourceType(); return dataSourceType; } //设置默认的数据源 @Override public void setDefaultTargetDataSource(Object
defaultTargetDataSource) { super .setDefaultTargetDataSource(defaultTargetDataSource); } //设置数据源集合. @Override public void setTargetDataSources(Map
targetDataSources) { super .setTargetDataSources(targetDataSources); } |
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
|
/** *数据源线程上下文对象. * */ public class DataSourceContextHolder
{ private static final ThreadLocal
contextHolder= new ThreadLocal(); public static void setDataSourceType(DataSourceType
dataSourceType){ contextHolder.set(dataSourceType); } public static DataSourceType
getDataSourceType(){ return (DataSourceType)
contextHolder.get(); } public static void clearDataSourceType(){ contextHolder.remove(); } } |
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
|
/** *
初始化动态数据源 *
@author Administrator * */ /** *
初始化动态数据源 *
@author Administrator * */ @Component ( "mutiGameDs" ) public class MutiDataSourceBean extends AbstractRoutingDataSource implements ApplicationContextAware{ private static Logger
log = Logger.getLogger( "InistailizeMutiDataSourceBean" ); private static ApplicationContext
ac ; @Override public void afterPropertiesSet()
{ log.info( "初始化多数据源" ); try { initailizeMutiDataSource(); } catch (Exception
e) { //
TODO Auto-generated catch block e.printStackTrace(); } log.info( "多数据源加入spring容器中成功!" ); super .afterPropertiesSet(); } @Override public void setApplicationContext(ApplicationContext
ctx) throws BeansException
{ //
TODO Auto-generated method stub ac=ctx; } private void initailizeMutiDataSource() throws Exception{ Document
doc = XmlUtils.loadXMLClassPath( "game-ds.xml" ); List
servers = doc.selectNodes( "//server" ); DruidDataSource
ds = null ; ..... .... .. . DefaultListableBeanFactory
acf = (DefaultListableBeanFactory)ac.getAutowireCapableBeanFactory(); Map<Object,DruidDataSource>
dsMap = new HashMap<Object,
DruidDataSource>(); for (Object
object : servers) { Element
el =(Element)object; ds
= new DruidDataSource(); String
id = el.attributeValue( "id" ); String
username = el.attributeValue( "username" ); String
url = el.attributeValue( "url" ); String
pwd = el.attributeValue( "pwd" ); ds.setUsername(username); ds.setUrl(url); ds.setPassword(pwd); ds.setInitialSize(
Integer.valueOf(initialSize)); ds.setMaxActive(Integer.valueOf(maxActive)); ds.setMinIdle(Integer.valueOf(minIdle)); ds.setMaxWait(Integer.valueOf(maxWait)); ds.setTestOnBorrow(testOnBorrow.equals( "true" )? true : false ); ds.setTestOnReturn(testOnReturn.equals( "true" )? true : false ); ds.setTestWhileIdle(testWhileIdle.equals( "true" )? true : false ); ds.setTimeBetweenEvictionRunsMillis(Long.valueOf(timeBetweenEvictionRunsMillis)); ds.setMinEvictableIdleTimeMillis(Long.valueOf(minEvictableIdleTimeMillis)); ds.setRemoveAbandoned(removeAbandoned.equals( "true" )? true : false ); ds.setRemoveAbandonedTimeout(Integer.valueOf(removeAbandonedTimeout)); ds.setLogAbandoned(logAbandoned.equals( "true" )? true : false ); ds.setFilters(filters); acf.registerSingleton(id,
ds); dsMap.put(DataSourceType.valueOf(id),
ds); } this .setTargetDataSources(dsMap); setDefaultTargetDataSource(dsMap.get( "game_server_1" )); //设置默认数据源 } @Override protected Object
determineCurrentLookupKey() { DataSourceType
dataSourceType= DataSourceContextHolder.getDataSourceType(); return dataSourceType; } @Override public void setDataSourceLookup(DataSourceLookup
dataSourceLookup) { super .setDataSourceLookup(dataSourceLookup); } @Override public void setDefaultTargetDataSource(Object
defaultTargetDataSource) { super .setDefaultTargetDataSource(defaultTargetDataSource); } @Override public void setTargetDataSources(Map
targetDataSources) { super .setTargetDataSources(targetDataSources); } } |
xml
<bean id="sessionFactory"
class="org.springframework.orm.hibernate3.annotation.AnnotationSessionFactoryBean">
<property name="hibernateProperties">
<props>
<prop key="hibernate.hbm2ddl.auto">false
</prop>
<prop key="hibernate.dialect">org.hibernate.dialect.Oracle9iDialect
</prop>
<prop key="hibernate.show_sql">true
</prop>
<prop key="hibernate.query.substitutions">true 1, false 0, yes ‘Y‘, no ‘N‘
</prop>
<prop key="hibernate.bytecode.use_reflection_optimizer">true
</prop>
<prop key="hibernate.cache.provider_class">org.hibernate.cache.EhCacheProvider
</prop>
<prop key="hibernate.cache.use_query_cache">true
</prop>
<prop key="hibernate.cache.use_structured_entries">false
</prop>
<prop key="hibernate.max_fetch_depth">0
</prop>
<prop key="hibernate.jdbc.fetch_size">50
</prop>
<prop key="hibernate.jdbc.batch_size">20
</prop>
</props>
</property>
<property name="dataSource">
<ref bean="mutiDataSourceBean" />
</property>
</bean>
<bean id="jdbcExceptionTranslator"
class="org.springframework.jdbc.support.SQLErrorCodeSQLExceptionTranslator">
<property name="dataSource">
<ref bean="mutiDataSourceBean" />
</property>
</bean>
<bean id="hibernateTemplate" class="org.springframework.orm.hibernate3.HibernateTemplate">
<property name="sessionFactory">
<ref bean="sessionFactory" />
</property>
<property name="jdbcExceptionTranslator">
<ref bean="jdbcExceptionTranslator" />
</property>
</bean>
<bean id="transactionManager"
class="org.springframework.orm.hibernate3.HibernateTransactionManager">
<property name="sessionFactory">
<ref local="sessionFactory" />
</property>
</bean>
<bean id="mutiDataSourceBean" class="com.mshop.common.dataSource.MutiDataSourceBean">
</bean>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
|
public class TestMutiDataSource extends SpringTxTestCase{ @Autowired @Qualifier ( "jdbcTemplate4Game" ) JdbcTemplate
jt; @Test public void test()
{ DataSourceContextHolder.setDataSourceType(DataSourceType.game_server_1); List<Map<String,
Object>> list = jt.queryForList( "select* from fs_accountlog.t_accountlogin" ); for (Map<String,
Object> map : list) { System.out.println(map); } } }
|
标签:
原文地址:http://blog.csdn.net/u012099568/article/details/51423837