Spring动态配置多数据源,即在大型应用中对数据进行切分,并且采用多个数据库实例进行管理,这样可以有效提高系统的水平伸缩性。而这样的方案就会不同于常见的单一数据实例的方案,这就要程序在运行时根据当时的请求及系统状态来动态的决定将数据存储在哪个数据库实例中,以及从哪个数据库提取数据。
Spring配置多数据源的方式和具体使用过程。
Spring对于多数据源,以数据库表为参照,大体上可以分成两大类情况:
一是,表级上的跨数据库。即,对于不同的数据库却有相同的表(表名和表结构完全相同)。
二是,非表级上的跨数据库。即,多个数据源不存在相同的表。
Spring2.x的版本中采用Proxy模式,就是我们在方案中实现一个虚拟的数据源,并且用它来封装数据源选择逻辑,这样就可以有效地将数据源选择逻辑从Client中分离出来。Client提供选择所需的上下文(因为这是Client所知道的),由虚拟的DataSource根据Client提供的上下文来实现数据源的选择。
具体的实现就是,虚拟的DataSource仅需继承AbstractRoutingDataSource实现determineCurrentLookupKey()在其中封装数据源的选择逻辑。
步骤如下:
一、动态配置多数据源
1. 数据源的名称常量类:
1
2
3
4
5
6
7
|
package
com.frogking.datasource;
public
class
DataSourceConst {
public
static
final
String Admin=
"12"
;
public
static
final
String User =
"123"
;
}
|
2. 建立一个获得和设置上下文环境的类,主要负责改变上下文数据源的名称:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
|
package
com.frogking.datasource;
package
com.frogking.datasource;
public
class
DataSourceContextHolder {
private
static
final
ThreadLocal contextHolder =
new
ThreadLocal();
// 线程本地环境
// 设置数据源类型
public
static
void
setDataSourceType(String dataSourceType) { contextHolder.set(dataSourceType);
}
// 获取数据源类型
public
static
String getDataSourceType() {
return
(String) contextHolder.get();
}
// 清除数据源类型
public
static
void
clearDataSourceType () {
contextHolder.remove();
}
}
|
3. 建立动态数据源类,注意,这个类必须继承AbstractRoutingDataSource,且实现方法 determineCurrentLookupKey,该方法返回一个Object,一般是返回字符串:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
|
package
com.frogking.datasource;
package
com.frogking.datasource;
import
org.springframework.jdbc.datasource.lookup.AbstractRoutingDataSource;
public
class
DynamicDataSource
extends
AbstractRoutingDataSource {
@Override
protected
Object determineCurrentLookupKey() {
return
DataSourceContextHolder.getDataSourceType();
}
}
|
4. 编写spring的配置文件配置多个数据源
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
|
<?
xml
version
=
"1.0"
encoding
=
"UTF-8"
?>
<
beans
xmlns
=
"http://www.springframework.org/schema/beans"
xmlns:xsi
=
"http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation
=
"http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd"
>
<!-- 数据源相同的内容 -->
<
bean
class
=
"org.springframework.jdbc.datasource.DriverManagerDataSource"
id
=
"parentDataSource"
>
<
property
name
=
"driverClassName"
value
=
"com.mysql.jdbc.Driver"
>
</
property
>
<
property
name
=
"username"
>
<
value
>root</
value
>
</
property
>
<
property
name
=
"password"
>
<
value
>root</
value
>
</
property
>
</
bean
>
<!-- 数据库test -->
<
bean
parent
=
"parentDataSource"
id
=
"adminDataSource"
>
<
property
name
=
"url"
>
<
value
>jdbc:mysql://localhost:3306/test</
value
>
</
property
>
</
bean
>
<!-- 数据库test1 -->
<
bean
parent
=
"parentDataSource"
id
=
"userDataSource"
>
<
property
name
=
"url"
>
<
value
>jdbc:mysql://localhost:3306/test2</
value
>
</
property
>
</
bean
>
<!-- 编写spring 配置文件的配置多数源映射关系 -->
<
bean
class
=
"com.frogking.datasource.DynamicDataSource"
id
=
"dataSource"
>
<
property
name
=
"targetDataSources"
>
<
map
key-type
=
"java.lang.String"
>
<
entry
value-ref
=
"adminDataSource"
key
=
"12"
></
entry
>
<
entry
value-ref
=
"userDataSource"
key
=
"123"
></
entry
>
</
map
>
</
property
>
<
property
name
=
"defaultTargetDataSource"
ref
=
"adminDataSource"
>
</
property
>
</
bean
>
<!-- sessionFactory的配置 -->
<
bean
class
=
"org.springframework.orm.hibernate3.LocalSessionFactoryBean"
id
=
"sessionFactory"
>
<
property
name
=
"dataSource"
>
<
ref
local
=
"dataSource"
></
ref
>
</
property
>
<!-- 实体映射资源 -->
<
property
name
=
"mappingResources"
>
<
list
>
<
value
>com/frogking/entity/User.hbm.xml</
value
>
<
value
>com/frogking/entity/Admin.hbm.xml</
value
>
</
list
>
</
property
>
<!-- 为sessionFactory配置Hibernate属性 -->
<
property
name
=
"hibernateProperties"
>
<
props
>
<
prop
key
=
"hibernate.dialect"
>
org.hibernate.dialect.MySQLDialect
</
prop
>
<
prop
key
=
"hibernate.show_sq"
>true</
prop
>
<
prop
key
=
"hibernate.connection.autocommit"
>false</
prop
>
<
prop
key
=
"hibernate.cache.use_query_cache"
>false</
prop
>
<
prop
key
=
"hibernate.max_fetch_depth"
>2</
prop
>
<
prop
key
=
"hibernate.bytecode.use_reflection_optimizer"
>
true
</
prop
>
</
props
>
</
property
>
</
bean
>
<
bean
id
=
"userDao"
class
=
"com.frogking.dao.impl.UserDaoImpl"
>
<
property
name
=
"sessionFactory"
ref
=
"sessionFactory"
></
property
>
</
bean
>
</
beans
>
|
5.删除Hibernate中表的配置文件catalog,他会自动匹配数据库如果指定catalog匹配将不启用
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
|
<?
xml
version
=
"1.0"
encoding
=
"utf-8"
?>
<!
DOCTYPE
hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<!--
Mapping file autogenerated by MyEclipse Persistence Tools
-->
<
hibernate-mapping
>
<
class
name
=
"com.frogking.entity.Admin"
table
=
"admin"
catalog
=
"test"
>
<
id
name
=
"id"
type
=
"java.lang.Integer"
>
<
column
name
=
"id"
/>
<
generator
class
=
"native"
/>
</
id
>
<
property
name
=
"name"
type
=
"java.lang.String"
>
<
column
name
=
"name"
length
=
"100"
/>
</
property
>
<
property
name
=
"passwrod"
type
=
"java.lang.String"
>
<
column
name
=
"passwrod"
length
=
"100"
/>
</
property
>
</
class
>
</
hibernate-mapping
>
|
六。写dao层
七。编写测试类测试是否成功
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
|
package
com.frogking.test;
import
static
org.junit.Assert.fail;
import
org.junit.Test;
import
org.springframework.context.ApplicationContext;
import
org.springframework.context.support.ClassPathXmlApplicationContext;
import
com.frogking.dao.IUserDao;
import
com.frogking.datasource.DataSourceConst;
import
com.frogking.datasource.DataSourceContextHolder;
import
com.frogking.entity.User;
public
class
UserTest {
ApplicationContext ac=
new
ClassPathXmlApplicationContext(
"applicationContext.xml"
);
IUserDao userDao =(IUserDao)ac.getBean(
"userDao"
);
@Test
public
void
testSave() {
//hibernate创建实体
DataSourceContextHolder.setDataSourceType(DataSourceConst.Admin);
//设置为另一个数据源
User user=
new
User();
user.setName(
"wzhhh"
);
user.setPassword(
"hhh"
);
userDao.save(user);
//使用dao保存实体
DataSourceContextHolder.setDataSourceType(DataSourceConst.User);
//设置为另一个数据源
userDao.save(user);
//使用dao保存实体到另一个库中
}
}
|