需要完整实例的同志们、想探讨问题的同胞们可以加QQ群:315309006
最近在做spring3+mybatis3整合,网上搜索了很多技术文章,都是实现动态切换数据源、或者是动态配置多数据源的,这里先声明一下,本文里面介绍的是运行时的动态维护,可以在系统运行期间动态增减数据源、并且可以根据需要切换数据源,笔者顺便鄙视下一些所谓开源的“大公司”的“大牛们”!
系统有一个默认的datasource(这个数据源是通过spring进行配置的),在这个datasource中维护了一张datasource表,用来维护其他的数据源(DynamicDataSource),表结构如下:动态数据源DynamicDataSource在spring的applicationContext.xml配置文件中定义如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
|
/**
* @author williams
* @descrice 多个登录用户可能需要同时切换数据源,所以这里需要写一个线程安全的ThreadLocal
* @more 用户切换数据源只要在程序中使用 DBContextHolder.setDBType("1") 即可完成数据源切换
*/
public class DBContextHolder {
private static final ThreadLocal<String> contextHolder = new ThreadLocal<String>();
public static void setDBType(String dbType) {
contextHolder.set(dbType);
}
public static String getDBType() {
return (String) contextHolder.get();
}
public static void clearDBType() {
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
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
|
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.SQLFeatureNotSupportedException;
import java.util.HashMap;
import java.util.Map;
import org.apache.commons.dbcp.BasicDataSource;
import org.apache.log4j.Logger;
import org.springframework.jdbc.datasource.lookup.AbstractRoutingDataSource;
/**
* @author williams
* @describe 实现动态数据源切换逻辑
*/
public class DynamicDataSource extends AbstractRoutingDataSource {
private Logger log = Logger.getLogger(this.getClass());
private Map<Object, Object> _targetDataSources;
/**
* @see org.springframework.jdbc.datasource.lookup.AbstractRoutingDataSource#determineCurrentLookupKey()
* @describe 数据源为空或者为0时,自动切换至默认数据源,即在配置文件中定义的dataSource数据源
*/
@Override
protected Object determineCurrentLookupKey() {
String dataSourceName = DBContextHolder.getDBType();
if (dataSourceName == null) {
dataSourceName = "dataSource";
} else {
this.selectDataSource(Integer.valueOf(dataSourceName));
if (dataSourceName.equals("0"))
dataSourceName = "dataSource";
}
log.debug("--------> use datasource " + dataSourceName);
return dataSourceName;
}
public void setTargetDataSources(Map<Object, Object> targetDataSources) {
this._targetDataSources = targetDataSources;
super.setTargetDataSources(this._targetDataSources);
afterPropertiesSet();
}
public void addTargetDataSource(String key, BasicDataSource dataSource) {
this._targetDataSources.put(key, dataSource);
this.setTargetDataSources(this._targetDataSources);
}
public BasicDataSource createDataSource(String driverClassName, String url,
String username, String password) {
BasicDataSource dataSource = new BasicDataSource();
dataSource.setDriverClassName(driverClassName);
dataSource.setUrl(url);
dataSource.setUsername(username);
dataSource.setPassword(password);
dataSource.setTestWhileIdle(true);
return dataSource;
}
/**
* @param serverId
* @describe 数据源存在时不做处理,不存在时创建新的数据源链接,并将新数据链接添加至缓存
*/
public void selectDataSource(Integer serverId) {
Object sid = DBContextHolder.getDBType();
if ("0".equals(serverId + "")) {
DBContextHolder.setDBType("0");
return;
}
Object obj = this._targetDataSources.get(serverId);
if (obj != null && sid.equals(serverId + "")) {
return;
} else {
BasicDataSource dataSource = this.getDataSource(serverId);
if (null != dataSource)
this.setDataSource(serverId, dataSource);
}
}
/**
* @describe 查询serverId对应的数据源记录
* @param serverId
*
@return
*/
public BasicDataSource getDataSource(Integer serverId) {
this.selectDataSource(0);
this.determineCurrentLookupKey();
Connection conn = null;
HashMap<String, Object> map = null;
try {
conn = this.getConnection();
PreparedStatement ps = conn
.prepareStatement("SELECT * FROM bas_datasource WHERE DBS_ID = ?");
ps.setInt(1, serverId);
ResultSet rs = ps.executeQuery();
map = new HashMap<String, Object>();
if (rs.next()) {
map.put("DBS_ID", rs.getInt("DBS_ID"));
map.put("DBS_DriverClassName", rs
.getString("DBS_DriverClassName"));
map.put("DBS_URL", rs.getString("DBS_URL"));
map.put("DBS_UserName", rs.getString("DBS_UserName"));
map.put("DBS_Password", rs.getString("DBS_Password"));
}
rs.close();
ps.close();
} catch (SQLException e) {
log.error(e);
} finally {
try {
conn.close();
} catch (SQLException e) {
log.error(e);
}
}
if (null != map) {
String driverClassName = map.get("DBS_DriverClassName").toString();
String url = map.get("DBS_URL").toString();
String userName = map.get("DBS_UserName").toString();
String password = map.get("DBS_Password").toString();
BasicDataSource dataSource = this.createDataSource(driverClassName,
url, userName, password);
return dataSource;
}
return null;
}
/**
* @param serverId
* @param dataSource
*/
public void setDataSource(Integer serverId, BasicDataSource dataSource) {
this.addTargetDataSource(serverId + "", dataSource);
DBContextHolder.setDBType(serverId + "");
}
}
|
探讨的同胞们可以加QQ群:315309006