resultMaps = ms.getResultMaps();
198 | builder.resultMaps(resultMaps);
199 | builder.resultSetType(ms.getResultSetType());
200 | // setStatementCache()
201 | builder.cache(ms.getCache());
202 | builder.flushCacheRequired(ms.isFlushCacheRequired());
203 | builder.useCache(ms.isUseCache());
204 | return builder.build();
205 | }
206 |
207 | /**
208 | * 根据msId获取接口类
209 | *
210 | * @param msId
211 | * @return
212 | * @throws ClassNotFoundException
213 | */
214 | public static Class> getMapperClass(String msId) {
215 | String mapperClassStr = msId.substring(0, msId.lastIndexOf("."));
216 | try {
217 | return Class.forName(mapperClassStr);
218 | } catch (ClassNotFoundException e) {
219 | throw new RuntimeException("无法获取Mapper接口信息:" + msId);
220 | }
221 | }
222 |
223 | /**
224 | * 获取执行的方法名
225 | *
226 | * @param ms
227 | * @return
228 | */
229 | public static String getMethodName(MappedStatement ms) {
230 | return getMethodName(ms.getId());
231 | }
232 |
233 | /**
234 | * 获取执行的方法名
235 | *
236 | * @param msId
237 | * @return
238 | */
239 | public static String getMethodName(String msId) {
240 | return msId.substring(msId.lastIndexOf(".") + 1);
241 | }
242 | }
243 |
--------------------------------------------------------------------------------
/tsharding-client/src/main/java/com/mogujie/trade/tsharding/route/orm/MapperHelperForSharding.java:
--------------------------------------------------------------------------------
1 | package com.mogujie.trade.tsharding.route.orm;
2 |
3 | import com.mogujie.trade.tsharding.annotation.ShardingExtensionMethod;
4 | import org.apache.ibatis.mapping.MappedStatement;
5 | import org.apache.ibatis.session.Configuration;
6 | import org.apache.ibatis.session.SqlSession;
7 |
8 | import java.lang.reflect.Method;
9 | import java.util.*;
10 |
11 | /**
12 | * Mapper处理主要逻辑,最关键的一个类
13 | *
14 | *
15 | * 参考项目地址 : https://github.com/abel533/Mapper
17 | *
18 | *
19 | * @author qigong on 5/1/15
20 | */
21 | public class MapperHelperForSharding {
22 |
23 | /**
24 | * 注册的通用Mapper接口
25 | */
26 | private Map, MapperEnhancer> registerMapper = new HashMap, MapperEnhancer>();
27 |
28 | /**
29 | * 缓存msid和MapperTemplate
30 | */
31 | private Map msIdCache = new HashMap();
32 | /**
33 | * 缓存skip结果
34 | */
35 | private final Map msIdSkip = new HashMap();
36 |
37 | /**
38 | * 缓存已经处理过的Collection
39 | */
40 | private Set> collectionSet = new HashSet>();
41 |
42 | /**
43 | * 是否使用的Spring
44 | */
45 | private boolean spring = false;
46 |
47 | /**
48 | * 是否为Spring4.x以上版本
49 | */
50 | private boolean spring4 = false;
51 |
52 | /**
53 | * Spring版本号
54 | */
55 | private String springVersion;
56 |
57 | /**
58 | * 缓存初始化时的SqlSession
59 | */
60 | private List sqlSessions = new ArrayList();
61 |
62 | /**
63 | * 针对Spring注入需要处理的SqlSession
64 | *
65 | * @param sqlSessions
66 | */
67 | public void setSqlSessions(SqlSession[] sqlSessions) {
68 | if (sqlSessions != null && sqlSessions.length > 0) {
69 | this.sqlSessions.addAll(Arrays.asList(sqlSessions));
70 | }
71 | }
72 |
73 | /**
74 | * Spring初始化方法,使用Spring时需要配置init-method="initMapper"
75 | */
76 | public void initMapper() {
77 | // 只有Spring会执行这个方法,所以Spring配置的时候,从这儿可以尝试获取Spring的版本
78 | // 先判断Spring版本,对下面的操作有影响
79 | // Spring4以上支持泛型注入,因此可以扫描通用Mapper
80 | if (!initSpringVersion()) {
81 | throw new RuntimeException("Error! Spring4 is necessary!");
82 | }
83 |
84 | for (SqlSession sqlSession : sqlSessions) {
85 | processConfiguration(sqlSession.getConfiguration());
86 | }
87 | }
88 |
89 | /**
90 | * 检测Spring版本号,Spring4.x以上支持泛型注入
91 | */
92 | private boolean initSpringVersion() {
93 | try {
94 | // 反射获取SpringVersion
95 | Class> springVersionClass = Class.forName("org.springframework.core.SpringVersion");
96 | springVersion = (String) springVersionClass.getDeclaredMethod("getVersion", new Class>[0]).invoke(null,
97 | new Object[0]);
98 | spring = true;
99 | if (springVersion.indexOf(".") > 0) {
100 | int MajorVersion = Integer.parseInt(springVersion.substring(0, springVersion.indexOf(".")));
101 | if (MajorVersion > 3) {
102 | spring4 = true;
103 | } else {
104 | spring4 = false;
105 | }
106 | }
107 | } catch (Exception e) {
108 | spring = false;
109 | spring4 = false;
110 | }
111 | return spring && spring4;
112 | }
113 |
114 | /**
115 | * 通过通用Mapper接口获取对应的MapperTemplate
116 | *
117 | * @param mapperClass
118 | */
119 | private MapperEnhancer fromMapperClass(Class> mapperClass) {
120 | Method[] methods = mapperClass.getDeclaredMethods();
121 | Class> templateClass = null;
122 | Class> tempClass = null;
123 | Set methodSet = new HashSet();
124 | for (Method method : methods) {
125 | if (method.isAnnotationPresent(ShardingExtensionMethod.class)) {
126 | ShardingExtensionMethod annotation = method.getAnnotation(ShardingExtensionMethod.class);
127 | tempClass = annotation.type();
128 | methodSet.add(method.getName());
129 | }
130 | if (templateClass == null) {
131 | templateClass = tempClass;
132 | } else if (templateClass != tempClass) {
133 | throw new RuntimeException("一个通用Mapper中只允许存在一个MapperTemplate子类!");
134 | }
135 | }
136 | if (templateClass == null || !MapperEnhancer.class.isAssignableFrom(templateClass)) {
137 | throw new RuntimeException("接口中不存在包含type为MapperTemplate的Provider注解,这不是一个合法的通用Mapper接口类!");
138 | }
139 | MapperEnhancer mapperEnhancer = null;
140 | try {
141 | mapperEnhancer = (MapperEnhancer) templateClass.getConstructor(Class.class).newInstance(mapperClass);
142 | } catch (Exception e) {
143 | throw new RuntimeException("实例化MapperTemplate对象失败:" + e.getMessage(), e);
144 | }
145 | // 注册方法
146 | for (String methodName : methodSet) {
147 | try {
148 | mapperEnhancer.addMethodMap(methodName, templateClass.getMethod("enhancedShardingSQL", MappedStatement.class, Configuration.class, Long.class));
149 | } catch (NoSuchMethodException e) {
150 | throw new RuntimeException(templateClass.getCanonicalName() + "中缺少enhancedShardingSQL方法!");
151 | }
152 | }
153 | return mapperEnhancer;
154 | }
155 |
156 | /**
157 | * 注册通用Mapper接口
158 | *
159 | * @param mapperClass
160 | * @throws Exception
161 | */
162 | public void registerMapper(Class> mapperClass) {
163 | if (registerMapper.get(mapperClass) == null) {
164 | MapperEnhancer enhancer = fromMapperClass(mapperClass);
165 | registerMapper.put(mapperClass, enhancer);
166 | } else {
167 | throw new RuntimeException("已经注册过的通用Mapper[" + mapperClass.getCanonicalName() + "]不能多次注册!");
168 | }
169 | }
170 |
171 | /**
172 | * 注册通用Mapper接口
173 | *
174 | * @param mapperClass
175 | * @throws Exception
176 | */
177 | public void registerMapper(String mapperClass) {
178 | try {
179 | registerMapper(Class.forName(mapperClass));
180 | } catch (ClassNotFoundException e) {
181 | throw new RuntimeException("注册通用Mapper[" + mapperClass + "]失败,找不到该通用Mapper!");
182 | }
183 | }
184 |
185 | /**
186 | * 方便Spring注入
187 | *
188 | * @param mappers
189 | */
190 | public void setMappers(String[] mappers) {
191 | if (mappers != null && mappers.length > 0) {
192 | for (String mapper : mappers) {
193 | registerMapper(mapper);
194 | }
195 | }
196 | }
197 |
198 | /**
199 | * 判断当前的接口方法是否需要进行拦截
200 | *
201 | * @param msId
202 | * @return
203 | */
204 | public boolean isMapperMethod(String msId) {
205 | if (msIdSkip.get(msId) != null) {
206 | return msIdSkip.get(msId);
207 | }
208 | for (Map.Entry, MapperEnhancer> entry : registerMapper.entrySet()) {
209 | if (entry.getValue().supportMethod(msId)) {
210 | msIdSkip.put(msId, true);
211 | return true;
212 | }
213 | }
214 | msIdSkip.put(msId, false);
215 | return false;
216 | }
217 |
218 | /**
219 | * 获取MapperTemplate
220 | *
221 | * @param msId
222 | * @return
223 | */
224 | private MapperEnhancer getMapperTemplate(String msId) {
225 | MapperEnhancer mapperEnhancer = null;
226 | if (msIdCache.get(msId) != null) {
227 | mapperEnhancer = msIdCache.get(msId);
228 | } else {
229 | for (Map.Entry, MapperEnhancer> entry : registerMapper.entrySet()) {
230 | if (entry.getValue().supportMethod(msId)) {
231 | mapperEnhancer = entry.getValue();
232 | break;
233 | }
234 | }
235 | msIdCache.put(msId, mapperEnhancer);
236 | }
237 | return mapperEnhancer;
238 | }
239 |
240 | /**
241 | * 重新设置SqlSource
242 | *
243 | * @param ms
244 | */
245 | public void setSqlSource(MappedStatement ms, Configuration configuration) {
246 | MapperEnhancer mapperEnhancer = getMapperTemplate(ms.getId());
247 | try {
248 | if (mapperEnhancer != null) {
249 | mapperEnhancer.setSqlSource(ms, configuration);
250 | }
251 | } catch (Exception e) {
252 | throw new RuntimeException("调用方法异常:" + e.getMessage(), e);
253 | }
254 | }
255 |
256 | /**
257 | * 处理configuration中全部的MappedStatement
258 | *
259 | * @param configuration
260 | */
261 | public void processConfiguration(Configuration configuration) {
262 | Collection collection = configuration.getMappedStatements();
263 | // 防止反复处理一个
264 | if (collectionSet.contains(collection)) {
265 | return;
266 | } else {
267 | collectionSet.add(collection);
268 | }
269 |
270 | Collection tmpCollection = new HashSet<>();
271 | tmpCollection.addAll(collection);
272 |
273 | Iterator iterator = tmpCollection.iterator();
274 | while (iterator.hasNext()) {
275 | Object object = iterator.next();
276 | if (object instanceof MappedStatement) {
277 | MappedStatement ms = (MappedStatement) object;
278 | if (isMapperMethod(ms.getId())) {
279 | setSqlSource(ms, configuration);
280 | }
281 | }
282 | }
283 | }
284 | }
--------------------------------------------------------------------------------
/tsharding-client/src/main/java/com/mogujie/trade/tsharding/route/orm/MapperResourceEnhancer.java:
--------------------------------------------------------------------------------
1 | package com.mogujie.trade.tsharding.route.orm;
2 |
3 | import com.mogujie.trade.tsharding.client.ShardingCaculator;
4 | import org.apache.ibatis.builder.StaticSqlSource;
5 | import org.apache.ibatis.mapping.MappedStatement;
6 | import org.apache.ibatis.mapping.ParameterMapping;
7 | import org.apache.ibatis.mapping.SqlSource;
8 | import org.apache.ibatis.scripting.defaults.RawSqlSource;
9 | import org.apache.ibatis.scripting.xmltags.*;
10 | import org.apache.ibatis.session.Configuration;
11 | import org.slf4j.Logger;
12 | import org.slf4j.LoggerFactory;
13 |
14 | import java.lang.reflect.Field;
15 | import java.util.ArrayList;
16 | import java.util.List;
17 |
18 | /**
19 | * Mappper sql增强
20 | *
21 | * @author qigong on 5/1/15
22 | */
23 | public class MapperResourceEnhancer extends MapperEnhancer{
24 |
25 | Logger logger = LoggerFactory.getLogger(MapperResourceEnhancer.class);
26 |
27 | public MapperResourceEnhancer(Class> mapperClass) {
28 | super(mapperClass);
29 | }
30 |
31 | public SqlSource enhancedShardingSQL(MappedStatement ms, Configuration configuration, Long shardingPara) {
32 |
33 | String tableName = ShardingCaculator.caculateTableName(shardingPara);
34 | SqlSource result = null;
35 |
36 | try {
37 | if (ms.getSqlSource() instanceof DynamicSqlSource) {
38 |
39 | DynamicSqlSource sqlSource = (DynamicSqlSource) ms.getSqlSource();
40 |
41 | Class sqlSourceClass = sqlSource.getClass();
42 |
43 | Field sqlNodeField = sqlSourceClass.getDeclaredField("rootSqlNode");
44 | sqlNodeField.setAccessible(true);
45 |
46 | MixedSqlNode rootSqlNode = (MixedSqlNode) sqlNodeField.get(sqlSource);
47 |
48 | Class mixedSqlNodeClass = rootSqlNode.getClass();
49 | Field contentsField = mixedSqlNodeClass.getDeclaredField("contents");
50 | contentsField.setAccessible(true);
51 | List textSqlNodes = (List) contentsField.get(rootSqlNode);
52 | List newSqlNodesList = new ArrayList();
53 |
54 | //StaticTextSqlNode
55 | Class textSqlNodeClass = textSqlNodes.get(0).getClass();
56 | Field textField = textSqlNodeClass.getDeclaredField("text");
57 | textField.setAccessible(true);
58 | for (SqlNode node : textSqlNodes) {
59 | if (node instanceof StaticTextSqlNode) {
60 | StaticTextSqlNode textSqlNode = (StaticTextSqlNode) node;
61 | String text = (String) textField.get(textSqlNode);
62 | if(!text.contains("TradeOrder")){
63 | newSqlNodesList.add(node);
64 | }else {
65 | newSqlNodesList.add(new StaticTextSqlNode(replaceWithShardingTableName(text, tableName, shardingPara)));
66 | }
67 | }else{
68 | newSqlNodesList.add(node);
69 | }
70 | }
71 |
72 | MixedSqlNode newrootSqlNode = new MixedSqlNode(newSqlNodesList);
73 | result = new DynamicSqlSource(configuration, newrootSqlNode);
74 | return result;
75 |
76 | } else if (ms.getSqlSource() instanceof RawSqlSource) {
77 |
78 | RawSqlSource sqlSource = (RawSqlSource) ms.getSqlSource();
79 | Class sqlSourceClass = sqlSource.getClass();
80 | Field sqlSourceField = sqlSourceClass.getDeclaredField("sqlSource");
81 | sqlSourceField.setAccessible(true);
82 | StaticSqlSource staticSqlSource = (StaticSqlSource) sqlSourceField.get(sqlSource);
83 | Field sqlField = staticSqlSource.getClass().getDeclaredField("sql");
84 | Field parameterMappingsField = staticSqlSource.getClass().getDeclaredField("parameterMappings");
85 | sqlField.setAccessible(true);
86 | parameterMappingsField.setAccessible(true);
87 |
88 | //sql处理
89 | String sql = (String) sqlField.get(staticSqlSource);
90 |
91 | if(!sql.contains("TradeOrder")){
92 | result = sqlSource;
93 | }else {
94 | sql = replaceWithShardingTableName(sql, tableName, shardingPara);
95 | result = new RawSqlSource(configuration, sql, null);
96 | //为sqlSource对象设置mappering参数
97 | StaticSqlSource newStaticSqlSource = (StaticSqlSource) sqlSourceField.get(result);
98 | List parameterMappings = (List)parameterMappingsField.get(staticSqlSource);
99 | parameterMappingsField.set(newStaticSqlSource, parameterMappings);
100 | }
101 | return result;
102 | } else {
103 | throw new RuntimeException("wrong sqlSource type!" + ms.getResource());
104 | }
105 |
106 | } catch (Exception e) {
107 | logger.error("reflect error!, ms resources:" + ms.getResource(), e);
108 | }
109 | return result;
110 | }
111 |
112 |
113 | private String replaceWithShardingTableName(String text, String tableName, Long shardingPara){
114 | if(text.contains(" TradeOrderPressureTest")){
115 | return text.replace(" TradeOrderPressureTest", " TradeOrderPressureTest" + ShardingCaculator.getNumberWithZeroSuffix(shardingPara));
116 | }
117 | return text.replace(" TradeOrder", " " + tableName);
118 | }
119 | }
120 |
--------------------------------------------------------------------------------
/tsharding-client/src/main/java/com/mogujie/trade/tsharding/route/orm/MapperScannerWithSharding.java:
--------------------------------------------------------------------------------
1 | package com.mogujie.trade.tsharding.route.orm;
2 |
3 | import com.mogujie.trade.db.DataSourceLookup;
4 | import com.mogujie.trade.db.ReadWriteSplittingDataSource;
5 | import com.mogujie.trade.tsharding.route.orm.base.*;
6 | import org.apache.ibatis.mapping.MappedStatement;
7 | import org.apache.ibatis.session.Configuration;
8 | import org.apache.ibatis.session.SqlSessionFactory;
9 | import org.mybatis.spring.SqlSessionFactoryBean;
10 | import org.springframework.beans.BeansException;
11 | import org.springframework.beans.factory.InitializingBean;
12 | import org.springframework.beans.factory.config.BeanFactoryPostProcessor;
13 | import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
14 | import org.springframework.core.io.Resource;
15 |
16 | import java.io.IOException;
17 | import java.lang.reflect.*;
18 | import java.util.HashMap;
19 | import java.util.HashSet;
20 | import java.util.Map;
21 | import java.util.Set;
22 |
23 | /**
24 | * Tsharding MybatisMapper的扫描类,负责将Mapper接口与对应的xml配置文件整合,绑定设定的数据源,注入到Spring Context中。
25 | *
26 | * @author qigong
27 | */
28 | public class MapperScannerWithSharding implements BeanFactoryPostProcessor, InitializingBean {
29 |
30 | public static DataSourceLookup dataSourceLookup;
31 |
32 | private String packageName;
33 |
34 | private Resource[] mapperLocations;
35 |
36 | private String[] mapperPacakages;
37 |
38 | private SqlSessionFactoryLookup sqlSessionFactoryLookup;
39 |
40 | public static DataSourceLookup getDataSourceLookup() {
41 | return dataSourceLookup;
42 | }
43 |
44 | @Override
45 | public void afterPropertiesSet() throws Exception {
46 | this.initMapperPackage();
47 | }
48 |
49 | private void initMapperPackage() throws IOException {
50 | this.mapperPacakages = packageName.split(",");
51 | }
52 |
53 | @Override
54 | public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
55 | this.dataSourceLookup = beanFactory.getBean(DataSourceLookup.class);
56 |
57 | try {
58 | this.initSqlSessionFactories(beanFactory);
59 | } catch (Exception e) {
60 | throw new RuntimeException(e);
61 | }
62 | ClassPathScanHandler scanner = new ClassPathScanHandler();
63 | Set> mapperClasses = new HashSet<>();
64 | for (String mapperPackage : this.mapperPacakages) {
65 | Set> classes = scanner.getPackageAllClasses(mapperPackage.trim(), false);
66 | mapperClasses.addAll(classes);
67 | }
68 | for (Class> clazz : mapperClasses) {
69 | if (isMapper(clazz)) {
70 | Object mapper = this.newMapper(clazz);
71 | beanFactory.registerSingleton(Character.toLowerCase(clazz.getSimpleName().charAt(0))
72 | + clazz.getSimpleName().substring(1), mapper);
73 | }
74 | }
75 |
76 | }
77 |
78 | private void initSqlSessionFactories(ConfigurableListableBeanFactory beanFactory) throws Exception {
79 | Map sqlSessionFactories = new HashMap<>(this.dataSourceLookup.getMapping().size());
80 |
81 | ReadWriteSplittingDataSource defaultDataSource = null;
82 | SqlSessionFactory defaultSqlSessionFactory = null;
83 | for (ReadWriteSplittingDataSource dataSource : this.dataSourceLookup.getMapping().values()) {
84 |
85 | SqlSessionFactoryBean sessionFactoryBean = new SqlSessionFactoryBean();
86 | sessionFactoryBean.setMapperLocations(mapperLocations);
87 | sessionFactoryBean.setDataSource(dataSource);
88 | sessionFactoryBean.setTypeAliasesPackage(this.packageName + ".domain.entity");
89 |
90 | // init 初始化所有sql对应的元数据、资源(sqlNode, sqlSource, mappedStatement)等
91 | sessionFactoryBean.afterPropertiesSet();
92 |
93 | if (defaultDataSource == null) {
94 | //第一个
95 | defaultDataSource = dataSource;
96 | defaultSqlSessionFactory = sessionFactoryBean.getObject();
97 | } else {
98 | SqlSessionFactory newSqlSessionFactory = sessionFactoryBean.getObject();
99 | Field conf = newSqlSessionFactory.getClass().getDeclaredField("configuration");
100 | conf.setAccessible(true);
101 | Configuration newConfiguration = (Configuration) conf.get(newSqlSessionFactory);
102 | Field mappedStatementField = newConfiguration.getClass().getDeclaredField("mappedStatements");
103 |
104 | //去掉final修饰符
105 | Field modifiersField = Field.class.getDeclaredField("modifiers");
106 | modifiersField.setAccessible(true);
107 | modifiersField.setInt( mappedStatementField, mappedStatementField.getModifiers() & ~Modifier.FINAL);
108 | mappedStatementField.setAccessible(true);
109 |
110 | //后续的元数据复用
111 | Configuration defaultConfiguration = defaultSqlSessionFactory.getConfiguration();
112 | Map reUsedMappedStatement = (Map) mappedStatementField.get(defaultConfiguration);
113 | mappedStatementField.set(newConfiguration, reUsedMappedStatement);
114 | }
115 | beanFactory.registerSingleton(dataSource.getName() + "SqlSessionFactory", sessionFactoryBean);
116 | sqlSessionFactories.put(dataSource.getName(), sessionFactoryBean.getObject());
117 | defaultSqlSessionFactory = sessionFactoryBean.getObject();
118 | }
119 |
120 | this.sqlSessionFactoryLookup = new SqlSessionFactoryLookup(sqlSessionFactories);
121 | }
122 |
123 | private boolean isMapper(Class> clazz) {
124 | if (clazz.isInterface()) {
125 | return true;
126 | }
127 | return false;
128 | }
129 |
130 | private Object newMapper(final Class> clazz) {
131 |
132 | final Invoker invoker = new TShardingRoutingInvokeFactory(sqlSessionFactoryLookup).newInvoker(clazz);
133 |
134 | return Proxy.newProxyInstance(clazz.getClassLoader(), new Class[]{clazz},
135 | new InvocationHandler() {
136 | @Override
137 | public Object invoke(Object proxy, final Method method, final Object[] args) throws Throwable {
138 | return invoker.invoke(new DefaultInvocation(method, args));
139 | }
140 | });
141 | }
142 |
143 | /**
144 | * 注入packageName配置
145 | *
146 | * @param packageName
147 | */
148 | public void setPackageName(String packageName) {
149 | this.packageName = packageName;
150 | }
151 |
152 | /**
153 | * 注入mapperLocations配置
154 | *
155 | * @param mapperLocations
156 | */
157 | public void setMapperLocations(Resource[] mapperLocations) {
158 | this.mapperLocations = mapperLocations;
159 | }
160 | }
161 |
162 |
163 |
--------------------------------------------------------------------------------
/tsharding-client/src/main/java/com/mogujie/trade/tsharding/route/orm/MapperShardingInitializer.java:
--------------------------------------------------------------------------------
1 | package com.mogujie.trade.tsharding.route.orm;
2 |
3 | import org.apache.ibatis.session.SqlSession;
4 | import org.apache.ibatis.session.SqlSessionFactory;
5 | import org.mybatis.spring.SqlSessionTemplate;
6 | import org.slf4j.Logger;
7 | import org.slf4j.LoggerFactory;
8 | import org.springframework.beans.BeansException;
9 | import org.springframework.context.ApplicationContext;
10 | import org.springframework.context.ApplicationContextAware;
11 |
12 | import java.util.ArrayList;
13 | import java.util.List;
14 | import java.util.Map;
15 |
16 | /**
17 | * 增强Mapper处理总入口:Mapper被mybatis初始化后,在这里做进一步的处理和增强
18 | *
19 | * @author qigong on 5/1/15
20 | */
21 | public class MapperShardingInitializer implements ApplicationContextAware {
22 |
23 |
24 | Logger logger = LoggerFactory.getLogger(getClass());
25 |
26 | private String needEnhancedClasses;
27 | private String[] needEnhancedClassesArray;
28 |
29 | @Override
30 | public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
31 | Map sqlSessionFactories = applicationContext.getBeansOfType(SqlSessionFactory.class);
32 | if (sqlSessionFactories.isEmpty()) {
33 | return;
34 | }
35 | MapperHelperForSharding mapperHelperForSharding = new MapperHelperForSharding();
36 | List sqlSessions = new ArrayList<>(sqlSessionFactories.size());
37 | for (SqlSessionFactory sqlSessionFactory : sqlSessionFactories.values()) {
38 | SqlSession sqlSession = new SqlSessionTemplate(sqlSessionFactory);
39 | sqlSessions.add(sqlSession);
40 | }
41 | //Mapper代码增强 每个方法扩展出一个ShardingMapper类,增强为512个方法。
42 | this.needEnhancedClassesArray = needEnhancedClasses.split(",");
43 | this.enhanceMapperClass();
44 | mapperHelperForSharding.setMappers(needEnhancedClassesArray);
45 | mapperHelperForSharding.setSqlSessions(sqlSessions.toArray(new SqlSession[0]));
46 | mapperHelperForSharding.initMapper();
47 | }
48 |
49 | private void enhanceMapperClass() {
50 | for (String mapperClass : needEnhancedClassesArray) {
51 | try {
52 | MapperEnhancer.enhanceMapperClass(mapperClass);
53 | } catch (Exception e) {
54 | logger.error("Enhance {} class error", mapperClass, e);
55 | }
56 | }
57 | }
58 |
59 | public void setNeedEnhancedClasses(String needEnhancedClasses) {
60 | this.needEnhancedClasses = needEnhancedClasses;
61 | }
62 | }
63 |
--------------------------------------------------------------------------------
/tsharding-client/src/main/java/com/mogujie/trade/tsharding/route/orm/base/ClassPathScanHandler.java:
--------------------------------------------------------------------------------
1 | package com.mogujie.trade.tsharding.route.orm.base;
2 |
3 | import org.slf4j.Logger;
4 | import org.slf4j.LoggerFactory;
5 |
6 | import java.io.File;
7 | import java.io.FileFilter;
8 | import java.io.IOException;
9 | import java.net.JarURLConnection;
10 | import java.net.URL;
11 | import java.net.URLDecoder;
12 | import java.util.Enumeration;
13 | import java.util.LinkedHashSet;
14 | import java.util.List;
15 | import java.util.Set;
16 | import java.util.jar.JarEntry;
17 | import java.util.jar.JarFile;
18 | import java.util.regex.Pattern;
19 |
20 | /**
21 | * 扫描指定包(包括jar)下的class文件
22 | * http://www.micmiu.com
23 | *
24 | * @author michael
25 | */
26 | public class ClassPathScanHandler {
27 |
28 | /**
29 | * logger
30 | */
31 | private static final Logger logger = LoggerFactory.getLogger(ClassPathScanHandler.class);
32 |
33 | /**
34 | * 是否排除内部类 true->是 false->否
35 | */
36 | private boolean excludeInner = true;
37 | /**
38 | * 过滤规则适用情况 true—>搜索符合规则的 false->排除符合规则的
39 | */
40 | private boolean checkInOrEx = true;
41 |
42 | /**
43 | * 过滤规则列表 如果是null或者空,即全部符合不过滤
44 | */
45 | private List classFilters = null;
46 |
47 | /**
48 | * 无参构造器,默认是排除内部类、并搜索符合规则
49 | */
50 | public ClassPathScanHandler() {
51 | }
52 |
53 | /**
54 | * excludeInner:是否排除内部类 true->是 false->否
55 | * checkInOrEx:过滤规则适用情况 true—>搜索符合规则的 false->排除符合规则的
56 | * classFilters:自定义过滤规则,如果是null或者空,即全部符合不过滤
57 | *
58 | * @param excludeInner
59 | * @param checkInOrEx
60 | * @param classFilters
61 | */
62 | public ClassPathScanHandler(Boolean excludeInner, Boolean checkInOrEx, List classFilters) {
63 | this.excludeInner = excludeInner;
64 | this.checkInOrEx = checkInOrEx;
65 | this.classFilters = classFilters;
66 |
67 | }
68 |
69 | /**
70 | * 扫描包
71 | *
72 | * @param basePackage
73 | * 基础包
74 | * @param recursive
75 | * 是否递归搜索子包
76 | * @return Set
77 | */
78 | public Set> getPackageAllClasses(String basePackage, boolean recursive) {
79 | Set> classes = new LinkedHashSet>();
80 | String packageName = basePackage;
81 | if (packageName.endsWith(".")) {
82 | packageName = packageName.substring(0, packageName.lastIndexOf('.'));
83 | }
84 | String package2Path = packageName.replace('.', '/');
85 |
86 | Enumeration dirs;
87 | try {
88 | dirs = Thread.currentThread().getContextClassLoader().getResources(package2Path);
89 | while (dirs.hasMoreElements()) {
90 | URL url = dirs.nextElement();
91 | String protocol = url.getProtocol();
92 | if ("file".equals(protocol)) {
93 | logger.info("扫描file类型的class文件....");
94 | String filePath = URLDecoder.decode(url.getFile(), "UTF-8");
95 | doScanPackageClassesByFile(classes, packageName, filePath, recursive);
96 | } else if ("jar".equals(protocol)) {
97 | logger.info("扫描jar文件中的类....");
98 | doScanPackageClassesByJar(packageName, url, recursive, classes);
99 | }
100 | }
101 | } catch (IOException e) {
102 | logger.error("IOException error:", e);
103 | }
104 |
105 | return classes;
106 | }
107 |
108 | /**
109 | * 以jar的方式扫描包下的所有Class文件
110 | *
111 | * @param basePackage
112 | * eg:michael.utils.
113 | * @param url
114 | * @param recursive
115 | * @param classes
116 | */
117 | private void doScanPackageClassesByJar(String basePackage, URL url, final boolean recursive, Set> classes) {
118 | String packageName = basePackage;
119 | String package2Path = packageName.replace('.', '/');
120 | JarFile jar;
121 | try {
122 | jar = ((JarURLConnection) url.openConnection()).getJarFile();
123 | Enumeration entries = jar.entries();
124 | while (entries.hasMoreElements()) {
125 | JarEntry entry = entries.nextElement();
126 | String name = entry.getName();
127 | if (!name.startsWith(package2Path) || entry.isDirectory()) {
128 | continue;
129 | }
130 |
131 | // 判断是否递归搜索子包
132 | if (!recursive && name.lastIndexOf('/') != package2Path.length()) {
133 | continue;
134 | }
135 | // 判断是否过滤 inner class
136 | if (this.excludeInner && name.indexOf('$') != -1) {
137 | logger.info("exclude inner class with name:" + name);
138 | continue;
139 | }
140 | String classSimpleName = name.substring(name.lastIndexOf('/') + 1);
141 | // 判定是否符合过滤条件
142 | if (this.filterClassName(classSimpleName)) {
143 | String className = name.replace('/', '.');
144 | className = className.substring(0, className.length() - 6);
145 | try {
146 | classes.add(Thread.currentThread().getContextClassLoader().loadClass(className));
147 | } catch (ClassNotFoundException e) {
148 | logger.error("Class.forName error:", e);
149 | }
150 | }
151 | }
152 | } catch (IOException e) {
153 | logger.error("IOException error:", e);
154 | }
155 | }
156 |
157 | /**
158 | * 以文件的方式扫描包下的所有Class文件
159 | *
160 | * @param packageName
161 | * @param packagePath
162 | * @param recursive
163 | * @param classes
164 | */
165 | private void doScanPackageClassesByFile(Set> classes, String packageName, String packagePath,
166 | boolean recursive) {
167 | File dir = new File(packagePath);
168 | if (!dir.exists() || !dir.isDirectory()) {
169 | return;
170 | }
171 | final boolean fileRecursive = recursive;
172 | File[] dirfiles = dir.listFiles(new FileFilter() {
173 | // 自定义文件过滤规则
174 | @Override
175 | public boolean accept(File file) {
176 | if (file.isDirectory()) {
177 | return fileRecursive;
178 | }
179 | String filename = file.getName();
180 | if (excludeInner && filename.indexOf('$') != -1) {
181 | logger.info("exclude inner class with name:" + filename);
182 | return false;
183 | }
184 | return filterClassName(filename);
185 | }
186 | });
187 | for (File file : dirfiles) {
188 | if (file.isDirectory()) {
189 | doScanPackageClassesByFile(classes, packageName + "." + file.getName(), file.getAbsolutePath(),
190 | recursive);
191 | } else {
192 | String className = file.getName().substring(0, file.getName().length() - 6);
193 | try {
194 | classes.add(Thread.currentThread().getContextClassLoader().loadClass(packageName + '.' + className));
195 |
196 | } catch (ClassNotFoundException e) {
197 | logger.error("IOException error:", e);
198 | }
199 | }
200 | }
201 | }
202 |
203 | /**
204 | * 根据过滤规则判断类名
205 | *
206 | * @param className
207 | * @return
208 | */
209 | private boolean filterClassName(String className) {
210 | if (!className.endsWith(".class")) {
211 | return false;
212 | }
213 | if (null == this.classFilters || this.classFilters.isEmpty()) {
214 | return true;
215 | }
216 | String tmpName = className.substring(0, className.length() - 6);
217 | boolean flag = false;
218 | for (String str : classFilters) {
219 | String tmpreg = "^" + str.replace("*", ".*") + "$";
220 | Pattern p = Pattern.compile(tmpreg);
221 | if (p.matcher(tmpName).find()) {
222 | flag = true;
223 | break;
224 | }
225 | }
226 | return checkInOrEx && flag || !checkInOrEx && !flag;
227 | }
228 |
229 | /**
230 | * @return the excludeInner
231 | */
232 | public boolean isExcludeInner() {
233 | return excludeInner;
234 | }
235 |
236 | /**
237 | * @return the checkInOrEx
238 | */
239 | public boolean isCheckInOrEx() {
240 | return checkInOrEx;
241 | }
242 |
243 | /**
244 | * @return the classFilters
245 | */
246 | public List getClassFilters() {
247 | return classFilters;
248 | }
249 |
250 | /**
251 | * @param pExcludeInner
252 | * the excludeInner to set
253 | */
254 | public void setExcludeInner(boolean pExcludeInner) {
255 | excludeInner = pExcludeInner;
256 | }
257 |
258 | /**
259 | * @param pCheckInOrEx
260 | * the checkInOrEx to set
261 | */
262 | public void setCheckInOrEx(boolean pCheckInOrEx) {
263 | checkInOrEx = pCheckInOrEx;
264 | }
265 |
266 | /**
267 | * @param pClassFilters
268 | * the classFilters to set
269 | */
270 | public void setClassFilters(List pClassFilters) {
271 | classFilters = pClassFilters;
272 | }
273 | }
--------------------------------------------------------------------------------
/tsharding-client/src/main/java/com/mogujie/trade/tsharding/route/orm/base/DefaultInvocation.java:
--------------------------------------------------------------------------------
1 | package com.mogujie.trade.tsharding.route.orm.base;
2 |
3 | import java.lang.reflect.Method;
4 | import java.util.Arrays;
5 |
6 | public class DefaultInvocation implements Invocation {
7 |
8 | private final Method method;
9 |
10 | private final Object[] args;
11 |
12 | public DefaultInvocation(Method method, Object[] args) {
13 | this.method = method;
14 | this.args = args;
15 | }
16 |
17 | @Override
18 | public Method getMethod() {
19 | return this.method;
20 | }
21 |
22 | @Override
23 | public Object[] getArgs() {
24 | return this.args;
25 | }
26 |
27 | @Override
28 | public String toString() {
29 | StringBuilder builder = new StringBuilder();
30 | builder.append("DefaultInvocation [");
31 | if (method != null) {
32 | builder.append("method=").append(method).append(", ");
33 | }
34 | if (args != null) {
35 | builder.append("args=").append(Arrays.toString(args));
36 | }
37 | builder.append("]");
38 | return builder.toString();
39 | }
40 |
41 | }
42 |
--------------------------------------------------------------------------------
/tsharding-client/src/main/java/com/mogujie/trade/tsharding/route/orm/base/Invocation.java:
--------------------------------------------------------------------------------
1 | package com.mogujie.trade.tsharding.route.orm.base;
2 |
3 | import java.lang.reflect.Method;
4 |
5 | /**
6 | * @author qigong
7 | *
8 | */
9 | public interface Invocation {
10 |
11 | Method getMethod();
12 |
13 | Object[] getArgs();
14 | }
15 |
--------------------------------------------------------------------------------
/tsharding-client/src/main/java/com/mogujie/trade/tsharding/route/orm/base/Invoker.java:
--------------------------------------------------------------------------------
1 | package com.mogujie.trade.tsharding.route.orm.base;
2 |
3 | /**
4 | * @author qigong
5 | *
6 | */
7 | public interface Invoker {
8 |
9 | Object invoke(Invocation invocation) throws Throwable;
10 | }
11 |
--------------------------------------------------------------------------------
/tsharding-client/src/main/java/com/mogujie/trade/tsharding/route/orm/base/InvokerFactory.java:
--------------------------------------------------------------------------------
1 | package com.mogujie.trade.tsharding.route.orm.base;
2 |
3 | /**
4 | * @author qigong
5 | *
6 | * @param
7 | */
8 | public interface InvokerFactory {
9 | Invoker newInvoker(T config);
10 | }
11 |
--------------------------------------------------------------------------------
/tsharding-client/src/main/java/com/mogujie/trade/tsharding/route/orm/base/MapperBasicConfig.java:
--------------------------------------------------------------------------------
1 | package com.mogujie.trade.tsharding.route.orm.base;
2 |
3 | /**
4 | * Mapper管控基础 类-数据源
5 | *
6 | * @author qigong
7 | *
8 | */
9 | public class MapperBasicConfig {
10 |
11 | private final Class> mapperInterface;
12 |
13 | private final String dataSourceName;
14 |
15 | public MapperBasicConfig(Class> mapperInterface, String dataSourceName) {
16 | this.mapperInterface = mapperInterface;
17 | this.dataSourceName = dataSourceName;
18 | }
19 |
20 | public Class> getMapperInterface() {
21 | return mapperInterface;
22 | }
23 |
24 | public String getDataSourceName() {
25 | return dataSourceName;
26 | }
27 |
28 | }
29 |
--------------------------------------------------------------------------------
/tsharding-client/src/main/java/com/mogujie/trade/tsharding/route/orm/base/MapperInitializeException.java:
--------------------------------------------------------------------------------
1 | package com.mogujie.trade.tsharding.route.orm.base;
2 |
3 | public class MapperInitializeException extends RuntimeException {
4 |
5 | private static final long serialVersionUID = -5010183715049161425L;
6 |
7 | public MapperInitializeException(String message) {
8 | super(message);
9 | }
10 |
11 | public MapperInitializeException(Throwable cause) {
12 | super(cause);
13 | }
14 |
15 | public MapperInitializeException(String message, Throwable cause) {
16 | super(message, cause);
17 | }
18 |
19 | public MapperInitializeException(String message, Throwable cause, boolean enableSuppression,
20 | boolean writableStackTrace) {
21 | super(message, cause, enableSuppression, writableStackTrace);
22 | }
23 |
24 | }
25 |
--------------------------------------------------------------------------------
/tsharding-client/src/main/java/com/mogujie/trade/tsharding/route/orm/base/ReadWriteSplittingContextInitializer.java:
--------------------------------------------------------------------------------
1 | package com.mogujie.trade.tsharding.route.orm.base;
2 |
3 | import com.mogujie.trade.db.DataSourceType;
4 | import com.mogujie.trade.db.ReadWriteSplitting;
5 | import com.mogujie.trade.db.ReadWriteSplittingContext;
6 | import org.slf4j.Logger;
7 | import org.slf4j.LoggerFactory;
8 |
9 | import java.lang.reflect.Method;
10 | import java.util.Map;
11 | import java.util.concurrent.ConcurrentHashMap;
12 |
13 | /**
14 | * 读写分离的上下文初始化和清空
15 | *
16 | * @author qigong
17 | */
18 | public class ReadWriteSplittingContextInitializer {
19 |
20 | private final static Logger logger = LoggerFactory.getLogger(ReadWriteSplittingContextInitializer.class);
21 |
22 | private final static String[] DEFAULT_WRITE_METHOD_NAMES = {"update", "save", "insert", "delete", "add",
23 | "batchInsert", "batchUpdate", "batchSave", "batchAdd"};
24 |
25 | private final static Map cache = new ConcurrentHashMap<>();
26 |
27 | public static void initReadWriteSplittingContext(Method method) {
28 | // 忽略object的方法,只关注Mapper的方法
29 | if (method.getDeclaringClass() != Object.class) {
30 | }
31 | DataSourceType dataSourceType = getDataSourceType(method);
32 | logger.debug("ReadWriteSplitting {} using dataSource of {}", method, dataSourceType);
33 |
34 | ReadWriteSplittingContext.set(dataSourceType);
35 | }
36 |
37 | public static void clearReadWriteSplittingContext() {
38 | ReadWriteSplittingContext.clear();
39 | }
40 |
41 | /**
42 | * 获取方法对应的数据眼类型
43 | *
44 | * @param method
45 | * @return
46 | */
47 | private static DataSourceType getDataSourceType(Method method) {
48 | DataSourceType dataSourceType = cache.get(method);
49 | if (dataSourceType == null) {
50 | synchronized (method) {
51 | dataSourceType = cache.get(method);
52 | if (dataSourceType == null) {
53 | dataSourceType = determineDataSourceType(method);
54 | cache.put(method, dataSourceType);
55 | }
56 | }
57 | }
58 | return dataSourceType;
59 | }
60 |
61 | private static DataSourceType determineDataSourceType(Method method) {
62 | DataSourceType dataSourceType = DataSourceType.slave;
63 |
64 | ReadWriteSplitting readWriteSplitting = method.getAnnotation(ReadWriteSplitting.class);
65 | if (readWriteSplitting != null) {
66 | dataSourceType = readWriteSplitting.value();
67 | dataSourceType = dataSourceType == null ? DataSourceType.master : dataSourceType;
68 | } else {
69 | for (String writeMethodName : DEFAULT_WRITE_METHOD_NAMES) {
70 | if (method.getName().startsWith(writeMethodName)) {
71 | dataSourceType = DataSourceType.master;
72 | break;
73 | }
74 | }
75 | }
76 | return dataSourceType;
77 | }
78 |
79 | }
80 |
--------------------------------------------------------------------------------
/tsharding-client/src/main/java/com/mogujie/trade/tsharding/route/orm/base/ReflectUtil.java:
--------------------------------------------------------------------------------
1 | package com.mogujie.trade.tsharding.route.orm.base;
2 |
3 | import java.lang.reflect.Field;
4 |
5 | /**
6 | * @author qigong on 15/9/17 下午8:05.
7 | */
8 | public class ReflectUtil {
9 |
10 | /**
11 | * 循环向上转型, 获取对象的 DeclaredField
12 | * @param object : 子类对象
13 | * @param fieldName : 父类中的属性名
14 | * @return 父类中的属性对象
15 | */
16 |
17 | public static Field getDeclaredField(Object object, String fieldName){
18 | Field field = null ;
19 | Class> clazz = object.getClass() ;
20 | for(; clazz != Object.class ; clazz = clazz.getSuperclass()) {
21 | try {
22 | field = clazz.getDeclaredField(fieldName) ;
23 | return field ;
24 | } catch (Exception e) {
25 | }
26 | }
27 | return null;
28 | }
29 | }
30 |
--------------------------------------------------------------------------------
/tsharding-client/src/main/java/com/mogujie/trade/tsharding/route/orm/base/SqlSessionFactoryLookup.java:
--------------------------------------------------------------------------------
1 | package com.mogujie.trade.tsharding.route.orm.base;
2 |
3 | import org.apache.ibatis.session.SqlSessionFactory;
4 |
5 | import java.util.Collections;
6 | import java.util.HashMap;
7 | import java.util.Map;
8 |
9 | public class SqlSessionFactoryLookup {
10 |
11 | private Map mapping;
12 |
13 | public SqlSessionFactoryLookup(Map mapping) {
14 |
15 | Map tmpMap = new HashMap<>(mapping.size());
16 | tmpMap.putAll(mapping);
17 | this.mapping = Collections.unmodifiableMap(tmpMap);
18 | }
19 |
20 | public Map getMapping() {
21 | return this.mapping;
22 | }
23 |
24 | public SqlSessionFactory get(String name) {
25 | return this.mapping.get(name);
26 | }
27 | }
28 |
--------------------------------------------------------------------------------
/tsharding-client/src/main/java/com/mogujie/trade/tsharding/route/orm/base/TShardingRoutingInvokeFactory.java:
--------------------------------------------------------------------------------
1 | package com.mogujie.trade.tsharding.route.orm.base;
2 |
3 | import com.mogujie.trade.db.DataSourceRouting;
4 | import com.mogujie.trade.db.DataSourceRoutingException;
5 | import com.mogujie.trade.tsharding.annotation.parameter.ShardingBuyerPara;
6 | import com.mogujie.trade.tsharding.annotation.parameter.ShardingOrderPara;
7 | import com.mogujie.trade.tsharding.annotation.parameter.ShardingSellerPara;
8 | import com.mogujie.trade.tsharding.client.ShardingCaculator;
9 | import com.mogujie.trade.tsharding.route.TShardingRoutingHandler;
10 | import org.apache.ibatis.session.SqlSessionFactory;
11 | import org.mybatis.spring.mapper.MapperFactoryBean;
12 | import org.slf4j.Logger;
13 | import org.slf4j.LoggerFactory;
14 | import org.springframework.util.StringUtils;
15 |
16 | import java.lang.annotation.Annotation;
17 | import java.lang.reflect.Field;
18 | import java.lang.reflect.Method;
19 | import java.util.List;
20 |
21 | public class TShardingRoutingInvokeFactory implements InvokerFactory> {
22 |
23 | private final Logger logger = LoggerFactory.getLogger(getClass());
24 |
25 | private SqlSessionFactoryLookup sqlSessionFactoryLookup;
26 |
27 | public TShardingRoutingInvokeFactory(SqlSessionFactoryLookup sqlSessionFactoryLookup) {
28 | this.sqlSessionFactoryLookup = sqlSessionFactoryLookup;
29 | }
30 |
31 | @Override
32 | public Invoker newInvoker(Class> mapperInterface) {
33 |
34 | final DataSourceRouting dataSourceRouting = mapperInterface.getAnnotation(DataSourceRouting.class);
35 | final Class clazz = mapperInterface;
36 |
37 | if (dataSourceRouting != null && !StringUtils.isEmpty(dataSourceRouting.value())) { //使用配置的数据源
38 | logger.debug("TShardingRoutingInvokeFactory routing: emptyHandler and dataSourceRouting.value:" + dataSourceRouting.value());
39 | return new Invoker() {
40 | @Override
41 | public Object invoke(Invocation invocation) throws Throwable {
42 |
43 | MapperBasicConfig config = new MapperBasicConfig(clazz, dataSourceRouting.value());
44 | final Object mapper = newMyBatisMapper(config);
45 | try {
46 | ReadWriteSplittingContextInitializer.initReadWriteSplittingContext(invocation.getMethod());
47 | return invocation.getMethod().invoke(mapper, invocation.getArgs());
48 | } finally {
49 | ReadWriteSplittingContextInitializer.clearReadWriteSplittingContext();
50 | }
51 | }
52 | };
53 | } else if (dataSourceRouting != null && dataSourceRouting.handler() == TShardingRoutingHandler.class) { //使用Sharding数据源
54 | logger.debug("TShardingRoutingInvokeFactory routing: dynamic handler: " + dataSourceRouting.handler().getName());
55 | return new Invoker() {
56 | @Override
57 | public Object invoke(Invocation invocation) throws Throwable {
58 |
59 | Method method = invocation.getMethod();
60 | ShardingMetadata shardingMetadata = getShardingKey(method, invocation.getArgs());
61 |
62 | if (shardingMetadata == null) {
63 | throw new DataSourceRoutingException("dataSourceRouting error! Method Name:" + method.getName() + " shardingMetadata is null!");
64 | }
65 |
66 | //走分库分表环境
67 | logger.debug("TShardingRoutingInvokeFactory routing to sharding db. Method Name:" + method.getName() + ". ShardingKey:" + shardingMetadata.getShardingKey());
68 |
69 | Class newClass = clazz;
70 | if (!"".equals(shardingMetadata.getSchemaName())) {
71 | newClass = Class.forName(clazz.getCanonicalName() + "Sharding" + method.getName());
72 | }
73 | Method newMethod = newClass.getMethod(method.getName() + shardingMetadata.getTableSuffix(), method.getParameterTypes());
74 | MapperBasicConfig config = new MapperBasicConfig(newClass, shardingMetadata.getSchemaName());
75 | final Object mapper = newMyBatisMapper(config);
76 | try {
77 | ReadWriteSplittingContextInitializer.initReadWriteSplittingContext(invocation.getMethod());
78 | return newMethod.invoke(mapper, invocation.getArgs());
79 | } finally {
80 | ReadWriteSplittingContextInitializer.clearReadWriteSplittingContext();
81 | }
82 | }
83 | };
84 | } else {
85 | throw new DataSourceRoutingException("dataSourceRouting error! cannot find datasource");
86 | }
87 | }
88 |
89 |
90 | private ShardingMetadata getShardingKey(Method method, Object[] args) throws NoSuchFieldException, IllegalAccessException {
91 | Annotation[][] an = method.getParameterAnnotations();
92 | if (an.length > 0) {
93 | for (int i = 0; i < an.length; i++) {
94 | for (int j = 0; j < an[i].length; j++) {
95 | if (an[i][j] instanceof ShardingOrderPara || an[i][j] instanceof ShardingBuyerPara || an[i][j] instanceof ShardingSellerPara) {
96 | Long shardingKey = 0L;
97 | if (args[i] instanceof Long) {
98 | shardingKey = (Long) args[i];
99 | } else if (args[i] instanceof List) {
100 | shardingKey = (Long) ((List) args[i]).get(0);
101 | } else if (an[i][j] instanceof ShardingOrderPara && args[i] instanceof Object) {
102 | Field field = ReflectUtil.getDeclaredField(args[i], "orderId");
103 | field.setAccessible(true);
104 | shardingKey = (Long) field.get(args[i]);
105 | if (shardingKey == null) {
106 | field = ReflectUtil.getDeclaredField(args[i], "parentOrderId");
107 | field.setAccessible(true);
108 | shardingKey = (Long) field.get(args[i]);
109 | }
110 | } else if (an[i][j] instanceof ShardingBuyerPara && args[i] instanceof Object) {
111 | Field field = ReflectUtil.getDeclaredField(args[i], "buyerUserId");
112 | field.setAccessible(true);
113 | shardingKey = (Long) field.get(args[i]);
114 | } else if (an[i][j] instanceof ShardingSellerPara && args[i] instanceof Object) {
115 | Field field = ReflectUtil.getDeclaredField(args[i], "sellerUserId");
116 | field.setAccessible(true);
117 | shardingKey = (Long) field.get(args[i]);
118 | }
119 |
120 | String schemaName = null;
121 | if (an[i][j] instanceof ShardingOrderPara) {
122 | schemaName = ShardingCaculator.caculateSchemaName("orderId", shardingKey);
123 | } else if (an[i][j] instanceof ShardingBuyerPara) {
124 | schemaName = ShardingCaculator.caculateSchemaName("buyerUserId", shardingKey);
125 | } else if (an[i][j] instanceof ShardingSellerPara) {
126 | schemaName = ShardingCaculator.caculateSchemaName("sellerUserId", shardingKey);
127 | }
128 | ShardingMetadata shardingMetadata = new ShardingMetadata();
129 | shardingMetadata.setShardingKey(shardingKey);
130 | shardingMetadata.setTableSuffix(ShardingCaculator.getNumberWithZeroSuffix((shardingKey % 10000) % 512));
131 | shardingMetadata.setSchemaName(schemaName);
132 | return shardingMetadata;
133 | }
134 | }
135 | }
136 | }
137 | return null;
138 | }
139 |
140 | @SuppressWarnings("unchecked")
141 | private Object newMyBatisMapper(MapperBasicConfig config) {
142 | MapperFactoryBean mapperFactoryBean = new MapperFactoryBean();
143 | mapperFactoryBean.setMapperInterface(config.getMapperInterface());
144 | mapperFactoryBean.setSqlSessionFactory(this.getSqlSessionFactory(config.getDataSourceName(),
145 | config.getMapperInterface()));
146 | mapperFactoryBean.afterPropertiesSet();
147 | Object mapper = null;
148 | try {
149 | mapper = mapperFactoryBean.getObject();
150 | } catch (Exception e) {
151 | throw new MapperInitializeException(e);
152 | }
153 | return mapper;
154 | }
155 |
156 | private SqlSessionFactory getSqlSessionFactory(String dataSourceName, Class> mapperInterface) {
157 | if (StringUtils.isEmpty(dataSourceName)) {
158 | if (sqlSessionFactoryLookup.getMapping().size() == 1) {
159 | return sqlSessionFactoryLookup.getMapping().values().iterator().next();
160 | } else {
161 | throw new DataSourceRoutingException("can't decided the datasource of "
162 | + mapperInterface.getCanonicalName() + ",please add config by using @DataSourceRouting");
163 | }
164 | } else {
165 | SqlSessionFactory sqlSessionFactory = sqlSessionFactoryLookup.get(dataSourceName);
166 | if (sqlSessionFactory == null) {
167 | throw new DataSourceRoutingException("can't find datasource named " + dataSourceName
168 | + " while init!");
169 | }
170 | return sqlSessionFactory;
171 | }
172 | }
173 |
174 | private class ShardingMetadata {
175 |
176 | private Long shardingKey;
177 |
178 | private String schemaName;
179 |
180 | private String tableSuffix;
181 |
182 | public String getSchemaName() {
183 | return schemaName;
184 | }
185 |
186 | public void setSchemaName(String schemaName) {
187 | this.schemaName = schemaName;
188 | }
189 |
190 | public String getTableSuffix() {
191 | return tableSuffix;
192 | }
193 |
194 | public void setTableSuffix(String tableSuffix) {
195 | this.tableSuffix = tableSuffix;
196 | }
197 |
198 | public Long getShardingKey() {
199 | return shardingKey;
200 | }
201 |
202 | public void setShardingKey(Long shardingKey) {
203 | this.shardingKey = shardingKey;
204 | }
205 | }
206 | }
207 |
--------------------------------------------------------------------------------
/tsharding-client/src/main/resources/tesla/support/service-loader.xml:
--------------------------------------------------------------------------------
1 |
2 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
17 |
18 |
19 |
20 |
22 |
23 |
24 |
25 |
26 |
--------------------------------------------------------------------------------
/tsharding-client/src/test/java/com/mogujie/service/tsharding/bean/BaseOrder.java:
--------------------------------------------------------------------------------
1 | package com.mogujie.service.tsharding.bean;
2 |
3 |
4 | public abstract class BaseOrder {
5 |
6 | private Long orderId;
7 |
8 | private Long buyerUserId;
9 |
10 | private Long sellerUserId;
11 |
12 | private Long shipTime;
13 |
14 | public Long getShipTime() {
15 | return shipTime;
16 | }
17 |
18 | public void setShipTime(Long shipTime) {
19 | this.shipTime = shipTime;
20 | }
21 |
22 | public Long getOrderId() {
23 | return orderId;
24 | }
25 |
26 | public void setOrderId(Long orderId) {
27 | this.orderId = orderId;
28 | }
29 |
30 | public Long getBuyerUserId() {
31 | return buyerUserId;
32 | }
33 |
34 | public void setBuyerUserId(Long buyerUserId) {
35 | this.buyerUserId = buyerUserId;
36 | }
37 |
38 | public Long getSellerUserId() {
39 | return sellerUserId;
40 | }
41 |
42 | public void setSellerUserId(Long sellerUserId) {
43 | this.sellerUserId = sellerUserId;
44 | }
45 | }
46 |
--------------------------------------------------------------------------------
/tsharding-client/src/test/java/com/mogujie/service/tsharding/bean/ShopOrder.java:
--------------------------------------------------------------------------------
1 | package com.mogujie.service.tsharding.bean;
2 |
3 |
4 | public class ShopOrder extends BaseOrder {
5 |
6 | }
7 |
--------------------------------------------------------------------------------
/tsharding-client/src/test/java/com/mogujie/service/tsharding/dao/ShopOrderDao.java:
--------------------------------------------------------------------------------
1 | package com.mogujie.service.tsharding.dao;
2 |
3 | import com.mogujie.service.tsharding.bean.ShopOrder;
4 |
5 | import java.util.List;
6 |
7 | /**
8 | * @auther qigong on 6/5/15 8:50 PM.
9 | */
10 | public interface ShopOrderDao {
11 |
12 | /**
13 | * 根据店铺级订单ID获取订单信息(同一个买家)
14 | *
15 | * @param listShopOrderIds 店铺级订单ID集合
16 | * @return List
17 | */
18 | List getShopOrderByShopOrderIds(List listShopOrderIds);
19 |
20 | }
21 |
--------------------------------------------------------------------------------
/tsharding-client/src/test/java/com/mogujie/service/tsharding/dao/ShopOrderDaoImpl.java:
--------------------------------------------------------------------------------
1 | package com.mogujie.service.tsharding.dao;
2 |
3 | import com.mogujie.service.tsharding.bean.ShopOrder;
4 | import com.mogujie.service.tsharding.mapper.ShopOrderMapper;
5 | import org.springframework.beans.factory.annotation.Autowired;
6 | import org.springframework.stereotype.Service;
7 |
8 | import java.util.ArrayList;
9 | import java.util.HashSet;
10 | import java.util.List;
11 | import java.util.Set;
12 |
13 | /**
14 | * @auther qigong on 6/5/15 8:52 PM.
15 | */
16 | @Service("shopOrderDao")
17 | public class ShopOrderDaoImpl implements ShopOrderDao {
18 |
19 | @Autowired
20 | private ShopOrderMapper shopOrderMapper;
21 |
22 | @Override
23 | public List getShopOrderByShopOrderIds(List listShopOrderIds) {
24 | if (listShopOrderIds == null || listShopOrderIds.size() == 0) {
25 | return null;
26 | }
27 | Set setShopOrderIds = new HashSet();
28 | for (Long iShopOrderId : listShopOrderIds) {
29 | if (iShopOrderId > 0) {
30 | setShopOrderIds.add(iShopOrderId);
31 | }
32 | }
33 | return shopOrderMapper.getShopOrderByShopOrderIds(new ArrayList(setShopOrderIds));
34 | }
35 |
36 | }
37 |
--------------------------------------------------------------------------------
/tsharding-client/src/test/java/com/mogujie/service/tsharding/mapper/ShopOrderMapper.java:
--------------------------------------------------------------------------------
1 | package com.mogujie.service.tsharding.mapper;
2 |
3 | import com.mogujie.service.tsharding.bean.ShopOrder;
4 | import com.mogujie.trade.db.DataSourceRouting;
5 | import com.mogujie.trade.tsharding.annotation.ShardingExtensionMethod;
6 | import com.mogujie.trade.tsharding.annotation.parameter.ShardingOrderPara;
7 | import com.mogujie.trade.tsharding.route.TShardingRoutingHandler;
8 | import com.mogujie.trade.tsharding.route.orm.MapperResourceEnhancer;
9 | import org.apache.ibatis.annotations.Param;
10 |
11 | import java.util.List;
12 |
13 | @DataSourceRouting(handler = TShardingRoutingHandler.class)
14 | public interface ShopOrderMapper {
15 |
16 | @ShardingExtensionMethod(type = MapperResourceEnhancer.class, method = "enhancedShardingSQL")
17 | public ShopOrder getShopOrderByShopOrderId(@ShardingOrderPara Long shopOrderId);
18 |
19 | @ShardingExtensionMethod(type = MapperResourceEnhancer.class, method = "enhancedShardingSQL")
20 | public List getShopOrderByShopOrderIds(@ShardingOrderPara List shopOrderIds);
21 |
22 |
23 | @ShardingExtensionMethod(type = MapperResourceEnhancer.class, method = "enhancedShardingSQL")
24 | int batchUpdateShopOrderByShopOrderIds(@ShardingOrderPara @Param("shopOrderIds") List shopOrderIds, @Param("shopOrder") ShopOrder shopOrder);
25 |
26 | }
--------------------------------------------------------------------------------
/tsharding-client/src/test/java/com/mogujie/service/tsharding/test/BaseTest.java:
--------------------------------------------------------------------------------
1 | package com.mogujie.service.tsharding.test;
2 |
3 | import org.junit.runner.RunWith;
4 | import org.springframework.test.context.ContextConfiguration;
5 | import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
6 |
7 | /**
8 | * @author by jiuru on 16/7/14.
9 | */
10 |
11 | @RunWith(SpringJUnit4ClassRunner.class)
12 | @ContextConfiguration({"classpath:spring-test.xml"})
13 | public abstract class BaseTest {
14 |
15 |
16 | }
17 |
--------------------------------------------------------------------------------
/tsharding-client/src/test/java/com/mogujie/service/tsharding/test/TShardingTest.java:
--------------------------------------------------------------------------------
1 | package com.mogujie.service.tsharding.test;
2 |
3 | import com.mogujie.service.tsharding.bean.ShopOrder;
4 | import com.mogujie.service.tsharding.dao.ShopOrderDao;
5 | import com.mogujie.service.tsharding.mapper.ShopOrderMapper;
6 | import org.junit.Test;
7 | import org.slf4j.Logger;
8 | import org.slf4j.LoggerFactory;
9 | import org.springframework.beans.factory.annotation.Autowired;
10 | import org.springframework.util.Assert;
11 |
12 | import java.util.ArrayList;
13 | import java.util.List;
14 |
15 | /**
16 | * @author by jiuru on 16/7/14.
17 | */
18 | public class TShardingTest extends BaseTest {
19 |
20 | private final Logger logger = LoggerFactory.getLogger(TShardingTest.class);
21 |
22 | @Autowired
23 | private ShopOrderDao shopOrderDao;
24 |
25 |
26 | @Autowired
27 | private ShopOrderMapper shopOrderMapper;
28 |
29 |
30 | @Test
31 | public void testGetShopOrderByShopOrderIdsDao() {
32 | List orderIds = new ArrayList<>();
33 | orderIds.add(50000280834672L);
34 | List orders = shopOrderDao.getShopOrderByShopOrderIds(orderIds);
35 | Assert.isTrue(orders.get(0).getOrderId().equals(50000280834672L));
36 | }
37 |
38 | @Test
39 | public void testGetShopOrderByShopOrderIds() {
40 | List orderIds = new ArrayList<>();
41 | orderIds.add(50000280834672L);
42 | List orders = shopOrderMapper.getShopOrderByShopOrderIds(orderIds);
43 | Assert.isTrue(orders.get(0).getOrderId().equals(50000280834672L));
44 | }
45 |
46 | @Test
47 | public void testUpdateShopOrder() {
48 | List orderIds = new ArrayList<>();
49 | orderIds.add(50000280834672L);
50 | ShopOrder shopOrder = new ShopOrder();
51 | shopOrder.setShipTime(12345678L);
52 | int rows = shopOrderMapper.batchUpdateShopOrderByShopOrderIds(orderIds, shopOrder);
53 | Assert.isTrue(rows == 1);
54 | }
55 |
56 |
57 | }
58 |
--------------------------------------------------------------------------------
/tsharding-client/src/test/java/com/mogujie/service/tsharding/test/client/ShardingCaculatorTest.java:
--------------------------------------------------------------------------------
1 | package com.mogujie.service.tsharding.test.client;
2 |
3 | import com.mogujie.trade.tsharding.client.ShardingCaculator;
4 | import org.junit.Assert;
5 | import org.junit.Test;
6 |
7 | /**
8 | * @auther qigong on 5/29/15 8:28 AM.
9 | */
10 | public class ShardingCaculatorTest {
11 |
12 |
13 | @Test
14 | public void testCaculateTableName() {
15 |
16 | ShardingparaObj para = new ShardingparaObj();
17 | para.setName("buyerId");
18 | para.setValue(100000000L);
19 | Assert.assertEquals("TestTable0000", ShardingCaculator.caculateTableName(para.getValue()));
20 | para.setValue(100000128L);
21 | Assert.assertEquals("TestTable0128", ShardingCaculator.caculateTableName(para.getValue()));
22 | para.setValue(100000512L);
23 | Assert.assertEquals("TestTable0000", ShardingCaculator.caculateTableName(para.getValue()));
24 | }
25 |
26 | @Test
27 | public void testCaculateSchemaName() {
28 |
29 | ShardingparaObj para = new ShardingparaObj();
30 | para.setName("sellerUserId");
31 | para.setValue(100000000L);
32 | Assert.assertEquals("sellertestschema0000", ShardingCaculator.caculateSchemaName(para.getName(), para.getValue()));
33 | para.setValue(100000128L);
34 | Assert.assertEquals("sellertestschema0002", ShardingCaculator.caculateSchemaName(para.getName(), para.getValue()));
35 | para.setName("buyerUserId");
36 | para.setValue(100000512L);
37 | Assert.assertEquals("testschema0000", ShardingCaculator.caculateSchemaName(para.getName(), para.getValue()));
38 | }
39 |
40 | @Test
41 | public void testCaculateDatasourceName() {
42 |
43 | ShardingparaObj para = new ShardingparaObj();
44 | para.setName("sellerUserId");
45 | para.setValue(100000000L);
46 | Assert.assertEquals("seller_ds_0", ShardingCaculator.caculateDatasourceName(para.getName(), para.getValue()));
47 | para.setValue(100000128L);
48 | Assert.assertEquals("seller_ds_0", ShardingCaculator.caculateDatasourceName(para.getName(), para.getValue()));
49 | para.setName("buyerUserId");
50 | para.setValue(100000511L);
51 | Assert.assertEquals("buyer_ds_1", ShardingCaculator.caculateDatasourceName(para.getName(), para.getValue()));
52 | }
53 |
54 | @Test
55 | public void testgetNumberWithZeroSuffix(){
56 | Assert.assertEquals("0100", ShardingCaculator.getNumberWithZeroSuffix(100L));
57 | }
58 |
59 | private class ShardingparaObj {
60 | private String name;
61 | private Long value;
62 |
63 | public void setName(String name) {
64 | this.name = name;
65 | }
66 |
67 | public void setValue(Long value) {
68 | this.value = value;
69 | }
70 |
71 | public String getName() {
72 | return name;
73 | }
74 |
75 | public Long getValue() {
76 | return value;
77 | }
78 |
79 | }
80 | }
81 |
--------------------------------------------------------------------------------
/tsharding-client/src/test/resources/META-INF/support/datasource.xml:
--------------------------------------------------------------------------------
1 |
2 |
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 |
--------------------------------------------------------------------------------
/tsharding-client/src/test/resources/META-INF/support/service-loader.xml:
--------------------------------------------------------------------------------
1 |
2 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
17 |
18 |
19 |
20 |
22 |
23 |
24 |
25 |
26 |
--------------------------------------------------------------------------------
/tsharding-client/src/test/resources/app.properties:
--------------------------------------------------------------------------------
1 | tesla.application.name = test-service
2 | tesla.owner = tesla
3 | tesla.port = 20019
4 |
5 | tesla.invokerExecutor.corePoolSize = 24
6 | tesla.invokerExecutor.maxPoolSize = 96
7 | tesla.invokerExecutor.keepAliveSeconds = 60
8 | tesla.invokerExecutor.queueCapacity = 5120
9 |
10 | tesla.worker.threads=0
11 |
12 | tesla.registry.ignoreError = true
13 | tesla.monitorTask.timeSpan = 60000
14 |
15 | tesla.network.readIdleTimeout = 0
16 | tesla.network.compressThreshold = 1024
17 |
18 | tsharding.orm.mapperPacakge=com.mogujie.service.tsharding.mapper
19 | tsharding.needEnhancedClasses=com.mogujie.service.tsharding.mapper.ShopOrderMapper
--------------------------------------------------------------------------------
/tsharding-client/src/test/resources/jdbc.properties:
--------------------------------------------------------------------------------
1 | # trade0000 master
2 | trade0000.master.url=jdbc:mysql://127.0.0.1/trade0000
3 | trade0000.master.username=test
4 | trade0000.master.password=test
5 | trade0000.master.minPoolSize=0
6 | trade0000.master.maxPoolSize=10
7 | trade0000.master.initialPoolSize=0
8 | # trade0000 slave
9 | trade0000.slave.url=jdbc:mysql://127.0.0.1/trade0000
10 | trade0000.slave.username=test
11 | trade0000.slave.password=test
12 | trade0000.slave.minPoolSize=1
13 | trade0000.slave.maxPoolSize=24
14 | trade0000.slave.initialPoolSize=1
15 |
16 | # trade0001 master
17 | trade0001.master.url=jdbc:mysql://127.0.0.1/trade0001
18 | trade0001.master.username=test
19 | trade0001.master.password=test
20 | trade0001.master.minPoolSize=0
21 | trade0001.master.maxPoolSize=10
22 | trade0001.master.initialPoolSize=0
23 | # trade0001 slave
24 | trade0001.slave.url=jdbc:mysql://127.0.0.1/trade0001
25 | trade0001.slave.username=test
26 | trade0001.slave.password=test
27 | trade0001.slave.minPoolSize=1
28 | trade0001.slave.maxPoolSize=24
29 | trade0001.slave.initialPoolSize=1
30 |
31 | # trade0002 master
32 | trade0002.master.url=jdbc:mysql://127.0.0.1/trade0002
33 | trade0002.master.username=test
34 | trade0002.master.password=test
35 | trade0002.master.minPoolSize=0
36 | trade0002.master.maxPoolSize=10
37 | trade0002.master.initialPoolSize=0
38 | # trade0002 slave
39 | trade0002.slave.url=jdbc:mysql://127.0.0.1/trade0002
40 | trade0002.slave.username=test
41 | trade0002.slave.password=test
42 | trade0002.slave.minPoolSize=1
43 | trade0002.slave.maxPoolSize=24
44 | trade0002.slave.initialPoolSize=1
45 |
46 | # trade0003 master
47 | trade0003.master.url=jdbc:mysql://127.0.0.1/trade0003
48 | trade0003.master.username=test
49 | trade0003.master.password=test
50 | trade0003.master.minPoolSize=0
51 | trade0003.master.maxPoolSize=10
52 | trade0003.master.initialPoolSize=0
53 | # trade0003 slave
54 | trade0003.slave.url=jdbc:mysql://127.0.0.1/trade0003
55 | trade0003.slave.username=test
56 | trade0003.slave.password=test
57 | trade0003.slave.minPoolSize=1
58 | trade0003.slave.maxPoolSize=24
59 | trade0003.slave.initialPoolSize=1
60 |
61 | # trade0004 master
62 | trade0004.master.url=jdbc:mysql://127.0.0.1/trade0004
63 | trade0004.master.username=test
64 | trade0004.master.password=test
65 | trade0004.master.minPoolSize=0
66 | trade0004.master.maxPoolSize=10
67 | trade0004.master.initialPoolSize=0
68 | # trade0004 slave
69 | trade0004.slave.url=jdbc:mysql://127.0.0.1/trade0004
70 | trade0004.slave.username=test
71 | trade0004.slave.password=test
72 | trade0004.slave.minPoolSize=1
73 | trade0004.slave.maxPoolSize=24
74 | trade0004.slave.initialPoolSize=1
75 |
76 | # trade0005 master
77 | trade0005.master.url=jdbc:mysql://127.0.0.1/trade0005
78 | trade0005.master.username=test
79 | trade0005.master.password=test
80 | trade0005.master.minPoolSize=0
81 | trade0005.master.maxPoolSize=10
82 | trade0005.master.initialPoolSize=0
83 | # trade0005 slave
84 | trade0005.slave.url=jdbc:mysql://127.0.0.1/trade0005
85 | trade0005.slave.username=test
86 | trade0005.slave.password=test
87 | trade0005.slave.minPoolSize=1
88 | trade0005.slave.maxPoolSize=24
89 | trade0005.slave.initialPoolSize=1
90 |
91 | # trade0006 master
92 | trade0006.master.url=jdbc:mysql://127.0.0.1/trade0006
93 | trade0006.master.username=test
94 | trade0006.master.password=test
95 | trade0006.master.minPoolSize=0
96 | trade0006.master.maxPoolSize=10
97 | trade0006.master.initialPoolSize=0
98 | # trade0006 slave
99 | trade0006.slave.url=jdbc:mysql://127.0.0.1/trade0006
100 | trade0006.slave.username=test
101 | trade0006.slave.password=test
102 | trade0006.slave.minPoolSize=1
103 | trade0006.slave.maxPoolSize=24
104 | trade0006.slave.initialPoolSize=1
105 |
106 | # trade0007 master
107 | trade0007.master.url=jdbc:mysql://127.0.0.1/trade0007
108 | trade0007.master.username=test
109 | trade0007.master.password=test
110 | trade0007.master.minPoolSize=0
111 | trade0007.master.maxPoolSize=10
112 | trade0007.master.initialPoolSize=0
113 | # trade0007 slave
114 | trade0007.slave.url=jdbc:mysql://127.0.0.1/trade0007
115 | trade0007.slave.username=test
116 | trade0007.slave.password=test
117 | trade0007.slave.minPoolSize=1
118 | trade0007.slave.maxPoolSize=24
119 | trade0007.slave.initialPoolSize=1
120 |
121 | # xdtrade单库 master
122 | xdtrade.master.url=jdbc:mysql://127.0.0.1/trade
123 | xdtrade.master.username=test
124 | xdtrade.master.password=test
125 | xdtrade.master.minPoolSize=0
126 | xdtrade.master.maxPoolSize=10
127 | xdtrade.master.initialPoolSize=0
128 | # rootjie slave
129 | xdtrade.slave.url=jdbc:mysql://127.0.0.1/trade
130 | xdtrade.slave.username=test
131 | xdtrade.slave.password=test
132 | xdtrade.slave.minPoolSize=1
133 | xdtrade.slave.maxPoolSize=24
134 | xdtrade.slave.initialPoolSize=1
135 |
136 |
137 |
--------------------------------------------------------------------------------
/tsharding-client/src/test/resources/logback.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 | %d [%t] %5p \(%F:%L\) %M\(\) - %m%n
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
--------------------------------------------------------------------------------
/tsharding-client/src/test/resources/spring-test.xml:
--------------------------------------------------------------------------------
1 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
--------------------------------------------------------------------------------
/tsharding-client/src/test/resources/sqlmap/shoporder-mapper.xml:
--------------------------------------------------------------------------------
1 |
2 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 | shipTime=#{shopOrder.shipTime},
13 |
14 |
15 |
16 |
17 |
18 | orderId,
19 | buyerUserId,
20 | sellerUserId
21 |
22 |
23 |
24 |
33 |
34 |
45 |
46 |
47 |
48 | UPDATE TradeOrder
49 |
50 | where orderId in
51 |
52 | #{shopOrderId}
53 |
54 | limit 500
55 |
56 |
57 |
--------------------------------------------------------------------------------