1
|
public
abstract
class
AbstractRoutingDataSource
extends
AbstractDataSource
implements
InitializingBean
|
1
2
3
4
5
6
7
|
public
Connection getConnection()
throws
SQLException {
return
determineTargetDataSource().getConnection();
}
public
Connection getConnection(String username, String password)
throws
SQLException {
return
determineTargetDataSource().getConnection(username, password);
}
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
|
/**
* Retrieve the current target DataSource. Determines the
* {@link #determineCurrentLookupKey() current lookup key}, performs
* a lookup in the {@link #setTargetDataSources targetDataSources} map,
* falls back to the specified
* {@link #setDefaultTargetDataSource default target DataSource} if necessary.
* @see #determineCurrentLookupKey()
*/
protected
DataSource determineTargetDataSource() {
Assert.notNull(
this
.resolvedDataSources,
"DataSource router not initialized"
);
Object lookupKey = determineCurrentLookupKey();
DataSource dataSource =
this
.resolvedDataSources.get(lookupKey);
if
(dataSource ==
null
&& (
this
.lenientFallback || lookupKey ==
null
)) {
dataSource =
this
.resolvedDefaultDataSource;
}
if
(dataSource ==
null
) {
throw
new
IllegalStateException(
"Cannot determine target DataSource for lookup key ["
+ lookupKey +
"]"
);
}
return
dataSource;
}
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
|
package
com.datasource.test.util.database;
import
org.springframework.jdbc.datasource.lookup.AbstractRoutingDataSource;
/**
* 获取数据源(依赖于spring)
* @author linhy
*/
public
class
DynamicDataSource
extends
AbstractRoutingDataSource{
@Override
protected
Object determineCurrentLookupKey() {
return
DataSourceHolder.getDataSource();
}
}
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
|
package
com.datasource.test.util.database;
/**
* 数据源操作
* @author linhy
*/
public
class
DataSourceHolder {
//线程本地环境
private
static
final
ThreadLocal<String> dataSources =
new
ThreadLocal<String>();
//设置数据源
public
static
void
setDataSource(String customerType) {
dataSources.set(customerType);
}
//获取数据源
public
static
String getDataSource() {
return
(String) dataSources.get();
}
//清除数据源
public
static
void
clearDataSource() {
dataSources.remove();
}
}
|
1
2
|
@DataSource
(name=DataSource.slave1)
public
List getProducts(){
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
|
package
com.datasource.test.util.database;
import
java.lang.annotation.*;
@Target
({ElementType.METHOD, ElementType.TYPE})
@Retention
(RetentionPolicy.RUNTIME)
@Documented
public
@interface
DataSource {
String name()
default
DataSource.master;
public
static
String master =
"dataSource1"
;
public
static
String slave1 =
"dataSource2"
;
public
static
String slave2 =
"dataSource3"
;
}
|
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
|
<?
xml
version
=
"1.0"
encoding
=
"UTF-8"
?>
<!-- Spring 数据库相关配置 放在这里 -->
<
beans
xmlns
=
"http://www.springframework.org/schema/beans"
xmlns:xsi
=
"http://www.w3.org/2001/XMLSchema-instance"
xmlns:aop
=
"http://www.springframework.org/schema/aop"
xmlns:tx
=
"http://www.springframework.org/schema/tx"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop-3.0.xsd
http://www.springframework.org/schema/tx
http://www.springframework.org/schema/tx/spring-tx-3.0.xsd">
<
bean
id = "dataSource1" class = "com.mysql.jdbc.jdbc2.optional.MysqlDataSource">
<
property
name
=
"url"
value
=
"${db1.url}"
/>
<
property
name = "user" value = "${db1.user}"/>
<
property
name = "password" value = "${db1.pwd}"/>
<
property
name
=
"autoReconnect"
value
=
"true"
/>
<
property
name
=
"useUnicode"
value
=
"true"
/>
<
property
name
=
"characterEncoding"
value
=
"UTF-8"
/>
</
bean
>
<
bean
id = "dataSource2" class = "com.mysql.jdbc.jdbc2.optional.MysqlDataSource">
<
property
name
=
"url"
value
=
"${db2.url}"
/>
<
property
name = "user" value = "${db2.user}"/>
<
property
name = "password" value = "${db2.pwd}"/>
<
property
name
=
"autoReconnect"
value
=
"true"
/>
<
property
name
=
"useUnicode"
value
=
"true"
/>
<
property
name
=
"characterEncoding"
value
=
"UTF-8"
/>
</
bean
>
<
bean
id = "dataSource3" class = "com.mysql.jdbc.jdbc2.optional.MysqlDataSource">
<
property
name
=
"url"
value
=
"${db3.url}"
/>
<
property
name = "user" value = "${db3.user}"/>
<
property
name = "password" value = "${db3.pwd}"/>
<
property
name
=
"autoReconnect"
value
=
"true"
/>
<
property
name
=
"useUnicode"
value
=
"true"
/>
<
property
name
=
"characterEncoding"
value
=
"UTF-8"
/>
</
bean
>
<!-- 配置多数据源映射关系 -->
<
bean
id
=
"dataSource"
class
=
"com.datasource.test.util.database.DynamicDataSource"
>
<
property
name
=
"targetDataSources"
>
<
map
key-type
=
"java.lang.String"
>
<
entry
key
=
"dataSource1"
value-ref
=
"dataSource1"
></
entry
>
<
entry
key
=
"dataSource2"
value-ref
=
"dataSource2"
></
entry
>
<
entry
key
=
"dataSource3"
value-ref
=
"dataSource3"
></
entry
>
</
map
>
</
property
>
<!-- 默认目标数据源为你主库数据源 -->
<
property
name
=
"defaultTargetDataSource"
ref
=
"dataSource1"
/>
</
bean
>
<
bean
id
=
"sessionFactoryHibernate"
class
=
"org.springframework.orm.hibernate3.LocalSessionFactoryBean"
>
<
property
name
=
"dataSource"
ref
=
"dataSource"
/>
<
property
name
=
"hibernateProperties"
>
<
props
>
<
prop
key
=
"hibernate.dialect"
>com.datasource.test.util.database.ExtendedMySQLDialect</
prop
>
<
prop
key
=
"hibernate.show_sql"
>${SHOWSQL}</
prop
>
<
prop
key
=
"hibernate.format_sql"
>${SHOWSQL}</
prop
>
<
prop
key
=
"query.factory_class"
>org.hibernate.hql.classic.ClassicQueryTranslatorFactory</
prop
>
<
prop
key
=
"hibernate.connection.provider_class"
>org.hibernate.connection.C3P0ConnectionProvider</
prop
>
<
prop
key
=
"hibernate.c3p0.max_size"
>30</
prop
>
<
prop
key
=
"hibernate.c3p0.min_size"
>5</
prop
>
<
prop
key
=
"hibernate.c3p0.timeout"
>120</
prop
>
<
prop
key
=
"hibernate.c3p0.idle_test_period"
>120</
prop
>
<
prop
key
=
"hibernate.c3p0.acquire_increment"
>2</
prop
>
<
prop
key
=
"hibernate.c3p0.validate"
>true</
prop
>
<
prop
key
=
"hibernate.c3p0.max_statements"
>100</
prop
>
</
props
>
</
property
>
</
bean
>
<
bean
id
=
"hibernateTemplate"
class
=
"org.springframework.orm.hibernate3.HibernateTemplate"
>
<
property
name
=
"sessionFactory"
ref
=
"sessionFactoryHibernate"
/>
</
bean
>
<
bean
id
=
"dataSourceExchange"
class
=
"com.datasource.test.util.database.DataSourceExchange"
/>
<
bean
id
=
"transactionManager"
class
=
"org.springframework.orm.hibernate3.HibernateTransactionManager"
>
<
property
name
=
"sessionFactory"
ref
=
"sessionFactoryHibernate"
/>
</
bean
>
<
tx:advice
id
=
"txAdvice"
transaction-manager
=
"transactionManager"
>
<
tx:attributes
>
<
tx:method
name
=
"insert*"
propagation
=
"NESTED"
rollback-for
=
"Exception"
/>
<
tx:method
name
=
"add*"
propagation
=
"NESTED"
rollback-for
=
"Exception"
/>
<
tx:method
name
=
"update*"
propagation
=
"NESTED"
rollback-for
=
"Exception"
/>
<
tx:method
name
=
"modify*"
propagation
=
"NESTED"
rollback-for
=
"Exception"
/>
<
tx:method
name
=
"edit*"
propagation
=
"NESTED"
rollback-for
=
"Exception"
/>
<
tx:method
name
=
"del*"
propagation
=
"NESTED"
rollback-for
=
"Exception"
/>
<
tx:method
name
=
"save*"
propagation
=
"NESTED"
rollback-for
=
"Exception"
/>
<
tx:method
name
=
"send*"
propagation
=
"NESTED"
rollback-for
=
"Exception"
/>
<
tx:method
name
=
"get*"
read-only
=
"true"
/>
<
tx:method
name
=
"find*"
read-only
=
"true"
/>
<
tx:method
name
=
"query*"
read-only
=
"true"
/>
<
tx:method
name
=
"search*"
read-only
=
"true"
/>
<
tx:method
name
=
"select*"
read-only
=
"true"
/>
<
tx:method
name
=
"count*"
read-only
=
"true"
/>
</
tx:attributes
>
</
tx:advice
>
<
aop:config
>
<
aop:pointcut
id
=
"service"
expression
=
"execution(* com.datasource..*.service.*.*(..))"
/>
<!-- 关键配置,切换数据源一定要比持久层代码更先执行(事务也算持久层代码) -->
<
aop:advisor
advice-ref
=
"txAdvice"
pointcut-ref
=
"service"
order
=
"2"
/>
<
aop:advisor
advice-ref
=
"dataSourceExchange"
pointcut-ref
=
"service"
order
=
"1"
/>
</
aop:config
>
</
beans
>
|