文章目录

涉及到spring aop

下面是 applicationContext.xml

需要多配置两个读的数据源

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
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
<?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:p="http://www.springframework.org/schema/p"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:aop="http://www.springframework.org/schema/aop"
xmlns:tx="http://www.springframework.org/schema/tx"
xmlns:mvc="http://www.springframework.org/schema/mvc"
xmlns:mongo="http://www.springframework.org/schema/data/mongo"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-3.0.xsd
http://www.springframework.org/schema/tx
http://www.springframework.org/schema/tx/spring-tx-3.0.xsd
http://www.springframework.org/schema/mvc
http://www.springframework.org/schema/mvc/spring-mvc.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop-3.0.xsd
http://www.springframework.org/schema/data/mongo
http://www.springframework.org/schema/data/mongo/spring-mongo-1.0.xsd">
<!-- 扫描类包,将标注Spring注解的类自动转化Bean,同时完成Bean的注入 -->
<context:component-scan base-package="com" />
<!-- 配置数据源 destroy-method="close"-->
<!-- <bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource" >
<property name="driverClass">
<value>${jdbc.driverClassName}</value>
</property>
<property name="jdbcUrl">
<value>${jdbc.url}</value>
</property>
<property name="user">
<value>${jdbc.username}</value>
</property>
<property name="password">
<value>${jdbc.password}</value>
</property>
连接池中保留的最小连接数。
<property name="minPoolSize">
<value>5</value>
</property>
连接池中保留的最大连接数。Default: 15
<property name="maxPoolSize">
<value>30</value>
</property>
初始化时获取的连接数,取值应在minPoolSize与maxPoolSize之间。Default: 3
<property name="initialPoolSize">
<value>10</value>
</property>
最大空闲时间,60秒内未使用则连接被丢弃。若为0则永不丢弃。Default: 0
<property name="maxIdleTime">
<value>60</value>
</property>
当连接池中的连接耗尽的时候c3p0一次同时获取的连接数。Default: 3
<property name="acquireIncrement">
<value>5</value>
</property>
JDBC的标准参数,用以控制数据源内加载的PreparedStatements数量。但由于预缓存的statements 属于单个connection而不是整个连接池。所以设置这个参数需要考虑到多方面的因素。
如果maxStatements与maxStatementsPerConnection均为0,则缓存被关闭。Default: 0
<property name="maxStatements">
<value>0</value>
</property>
每60秒检查所有连接池中的空闲连接。Default: 0
<property name="idleConnectionTestPeriod">
<value>60</value>
</property>
定义在从数据库获取新连接失败后重复尝试的次数。Default: 30
<property name="acquireRetryAttempts">
<value>30</value>
</property>
获取连接失败将会引起所有等待连接池来获取连接的线程抛出异常。但是数据源仍有效 保留,并在下次调用getConnection()的时候继续尝试获取连接。如果设为true,那么在尝试
获取连接失败后该数据源将申明已断开并永久关闭。Default: false
<property name="breakAfterAcquireFailure">
<value>true</value>
</property>
因性能消耗大请只在需要的时候使用它。如果设为true那么在每个connection提交的 时候都将校验其有效性。建议使用idleConnectionTestPeriod或automaticTestTable
等方法来提升连接测试的性能。Default: false
<property name="testConnectionOnCheckout">
<value>false</value>
</property>
<property name="automaticTestTable">
<value>true</value>
</property>
</bean>
<bean id="dynamicDataSource" class="com.hyjf.datasource.DynamicDataSource">
<property name="targetDataSources">
<map key-type="java.lang.String">
<entry value-ref="dataSourceWrite" key="dataSourceWrite"></entry>
<entry value-ref="dataSourceRead1" key="dataSourceRead1"></entry>
<entry value-ref="dataSourceRead2" key="dataSourceRead2"></entry>
</map>
</property>
<property name="defaultTargetDataSource" ref="dataSourceWrite">
</property>
</bean>
<bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
<property name="configLocation" value="classpath:Configuration.xml" />
<property name="dataSource" ref="dataSource" />
</bean>
<bean id="sqlSessionTemplate"
class="org.mybatis.spring.SqlSessionTemplate">
<constructor-arg index="0" ref="sqlSessionFactory" />
</bean>
配置事务管理器
<bean id="transactionManager"
class="org.springframework.jdbc.datasource.DataSourceTransactionManager"
p:dataSource-ref="dataSource" />
通过AOP配置提供事务增强,让controller包下所有Bean的所有方法拥有事务
<aop:config proxy-target-class="true">
<aop:pointcut id="serviceMethod"
expression=" execution(* com.controller.*..*(..))" />
<aop:advisor pointcut-ref="serviceMethod" advice-ref="txAdvice" />
</aop:config>
<tx:advice id="txAdvice" transaction-manager="transactionManager">
<tx:attributes>
<tx:method name="*" />
</tx:attributes>
</tx:advice> -->
<!-- 主从分离根据方法名 -->
<!-- AOP式方法级权限检查 -->
<aop:config proxy-target-class="true"></aop:config>
<!-- service切面查询方法拦截 -->
<!-- <aop:config>
<aop:pointcut
expression="execution(* com..*Service.query*(..))"
id="readBeforeQuery" />
<aop:advisor advice-ref="beforeRead" pointcut-ref="readBeforeQuery" />
</aop:config>
<aop:config>
<aop:pointcut
expression="execution(* com..*Service.query*(..))"
id="readAfterQuery" />
<aop:advisor advice-ref="afterRead" pointcut-ref="readAfterQuery" />
</aop:config>
<aop:config>
<aop:pointcut
expression="execution(* com..*Service.get*(..))"
id="readBeforeGet" />
<aop:advisor advice-ref="beforeRead" pointcut-ref="readBeforeGet" />
</aop:config>
<aop:config>
<aop:pointcut
expression="execution(* com..*Service.get*(..))"
id="readAfterGet" />
<aop:advisor advice-ref="afterRead" pointcut-ref="readAfterGet" />
</aop:config>
<aop:config>
<aop:pointcut
expression="execution(* com..*Service.select*(..))"
id="readBeforeSelect" />
<aop:advisor advice-ref="beforeRead" pointcut-ref="readBeforeSelect" />
</aop:config>
<aop:config>
<aop:pointcut
expression="execution(* com..*Service.select*(..))"
id="readAfterSelect" />
<aop:advisor advice-ref="afterRead" pointcut-ref="readAfterSelect" />
</aop:config>
<aop:config>
<aop:pointcut
expression="execution(* com..*Service.count*(..))"
id="readBeforeCount" />
<aop:advisor advice-ref="beforeRead" pointcut-ref="readBeforeCount" />
</aop:config>
<aop:config>
<aop:pointcut
expression="execution(* com..*Service.count*(..))"
id="readAfterCount" />
<aop:advisor advice-ref="afterRead" pointcut-ref="readAfterCount" />
</aop:config>
<aop:config>
<aop:pointcut
expression="execution(* com..*Service.search*(..))"
id="readBeforeCountSearch" />
<aop:advisor advice-ref="beforeRead" pointcut-ref="readBeforeCountSearch" />
</aop:config>
<aop:config>
<aop:pointcut
expression="execution(* com..*Service.search*(..))"
id="readAfterCountSearch" />
<aop:advisor advice-ref="afterRead" pointcut-ref="readAfterCountSearch" />
</aop:config> -->
</beans>

下面是比较重要的datasource实现的代码
DynamicDataSource.java

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
/*
* Copyright(c) 2012-2014 JD Pharma.Ltd. All Rights Reserved.
*/
package com.datasource;
import java.util.Random;
import java.util.ResourceBundle;
import org.springframework.jdbc.datasource.lookup.AbstractRoutingDataSource;
/**
*
* 此处为类说明
*/
public class DynamicDataSource extends AbstractRoutingDataSource {
public static String[] dataSourceArray;
public static String randomInt;
public static final Random random = new Random();
static {
ResourceBundle rb = ResourceBundle.getBundle("datasource");
randomInt = rb.getString("datasource.read.randomInt");
dataSourceArray = rb.getString("datasource.read").split(",");
}
@Override
protected Object determineCurrentLookupKey() {
return DatabaseContextHolder.getCustomerType();
}
public static String getRandomReadDataSource() {
return dataSourceArray[random.nextInt(Integer.parseInt(randomInt))];
}
}

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
/*
* Copyright(c) 2012-2014 JD Pharma.Ltd. All Rights Reserved.
*/
package com.datasource;
/**
*
* 此处为类说明
*/
public class DatabaseContextHolder {
private static final ThreadLocal<String> contextHolder = new ThreadLocal<String>();
public static void setCustomerType(String customerType) {
contextHolder.set(customerType);
}
public static String getCustomerType() {
return contextHolder.get();
}
public static void clearCustomerType() {
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
/*
* Copyright(c) 2012-2014 JD Pharma.Ltd. All Rights Reserved.
*/
package com.datasource.aop;
import java.lang.reflect.Method;
import org.springframework.aop.AfterReturningAdvice;
import org.springframework.stereotype.Component;
import com.datasource.DatabaseContextHolder;
/**
*
* 清除当前绑定的数据源
* @author renxingchen
*/
@Component("afterRead")
public class AfterReadAdvice implements AfterReturningAdvice {
/**
*
* 方法执行完毕清除当前绑定的数据源
* @param returnValue
* @param method
* @param args
* @param target
* @throws Throwable
* @see org.springframework.aop.AfterReturningAdvice#afterReturning(java.lang.Object,
* java.lang.reflect.Method, java.lang.Object[], java.lang.Object)
*/
@Override
public void afterReturning(Object returnValue, Method method, Object[] args, Object target) throws Throwable {
DatabaseContextHolder.clearCustomerType();
}
}
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
/*
* Copyright(c) 2012-2014 JD Pharma.Ltd. All Rights Reserved.
*/
package com.datasource.aop;
import java.lang.reflect.Method;
import org.springframework.aop.MethodBeforeAdvice;
import org.springframework.stereotype.Component;
import com.datasource.DatabaseContextHolder;
import com.datasource.DynamicDataSource;
/**
*
* 动态进行数据源的切换
*/
@Component("beforeRead")
public class BeforeReadAdvice implements MethodBeforeAdvice {
/**
*
* 动态进行数据源的切换
* @author
* @param method
* @param args
* @param target
* @throws Throwable
* @see org.springframework.aop.MethodBeforeAdvice#before(java.lang.reflect.Method,
* java.lang.Object[], java.lang.Object)
*/
@Override
public void before(Method method, Object[] args, Object target) throws Throwable {
String dataSourceName = DynamicDataSource.getRandomReadDataSource();
DatabaseContextHolder.setCustomerType(dataSourceName);
}
}

datasource.properties

1
2
datasource.read=dataSourceRead1,dataSourceRead2
datasource.read.randomInt=2
文章目录