package com.taobao.tddl.rule; import java.util.Arrays; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.Set; import com.google.common.collect.Lists; import com.taobao.tddl.rule.exceptions.RouteCompareDiffException; import com.taobao.tddl.rule.model.Field; import com.taobao.tddl.rule.model.MatcherResult; import com.taobao.tddl.rule.model.TargetDB; import com.taobao.tddl.rule.model.sqljep.Comparative; import com.taobao.tddl.rule.model.sqljep.ComparativeMapChoicer; import com.taobao.tddl.rule.utils.ComparativeStringAnalyser; import com.taobao.tddl.rule.utils.MatchResultCompare; /** * 类名取名兼容老的rule代码<br/> * 结合tddl的动态规则管理体系,获取对应{@linkplain VirtualTableRule} * 规则定义,再根据sql中condition或者是setParam()提交的参数计算出路由规则 {@linkplain MatcherResult} * * <pre> * condition简单语法: KEY CMP VALUE [:TYPE] * 1. KEY: 类似字段名字,用户随意定义 * 2. CMP: 链接符,比如< = > 等,具体可查看{@linkplain Comparative} * 3. VALUE: 对应的值,比如1 * 4. TYPE: 描述VALUE的类型,可选型,如果不填默认为Long类型。支持: int/long/string/date,可以使用首字母做为缩写,比如i/l/s/d。 * * 几个例子: * 1. id = 1 * 2. id = 1 : long * 3. id > 1 and id < 1 : long * 4. gmt_create = 2011-11-11 : date * 5. id in (1,2,3,4) : long * </pre> * * @author jianghang 2013-11-5 下午8:11:43 * @since 5.0.0 */ public class TddlRule extends TddlRuleConfig implements TddlTableRule { private VirtualTableRuleMatcher matcher = new VirtualTableRuleMatcher(); public MatcherResult route(String vtab, String condition) { return route(vtab, condition, super.getCurrentRule()); } public MatcherResult route(String vtab, String condition, String version) { return route(vtab, condition, super.getVersionRule(version)); } public MatcherResult route(String vtab, String condition, VirtualTableRoot specifyVtr) { return route(vtab, generateComparativeMapChoicer(condition), Lists.newArrayList(), specifyVtr); } public MatcherResult route(String vtab, ComparativeMapChoicer choicer, List<Object> args) { return route(vtab, choicer, args, super.getCurrentRule()); } public MatcherResult route(String vtab, ComparativeMapChoicer choicer, List<Object> args, String version) { return route(vtab, choicer, args, super.getVersionRule(version)); } public MatcherResult route(String vtab, ComparativeMapChoicer choicer, List<Object> args, VirtualTableRoot specifyVtr) { TableRule rule = specifyVtr.getVirtualTable(vtab); if (rule != null) { return matcher.match(choicer, args, rule, true); } else { // 不存在规则,返回默认的 return defaultRoute(vtab, specifyVtr); } } public MatcherResult routeMverAndCompare(boolean isSelect, String vtab, ComparativeMapChoicer choicer, List<Object> args) throws RouteCompareDiffException { if (super.getAllVersions().size() == 0) { throw new RuntimeException("routeWithMulVersion method just support multy version rule,use route method instead or config with multy version style!"); } // 如果只有单套规则,直接返回这套规则的路由结果 if (super.getAllVersions().size() == 1) { return route(vtab, choicer, args, super.getCurrentRule()); } // 如果不止一套规则,那么计算两套规则,默认都返回新规则 if (super.getAllVersions().size() != 2) { throw new RuntimeException("not support more than 2 copy rule compare"); } // 第一个排位的为旧规则 MatcherResult oldResult = route(vtab, choicer, args, super.getCurrentRule()); if (isSelect) { return oldResult; } else { // 第二个排位的为新规则 MatcherResult newResult = route(vtab, choicer, args, super.getVersionRule(super.getAllVersions().get(1))); boolean compareResult = MatchResultCompare.matchResultCompare(newResult, oldResult); if (compareResult) { return oldResult; } else { throw new RouteCompareDiffException("sql type is not-select,rule calculate result diff"); } } } // ================ helper method ================ /** * 没有分库分表的逻辑表,返回指定库表 * * @param vtab * @param vtrCurrent * @return */ private MatcherResult defaultRoute(String vtab, VirtualTableRoot vtrCurrent) { TargetDB targetDb = new TargetDB(); // 设置默认的链接库,比如就是groupKey targetDb.setDbIndex(this.getDefaultDbIndex(vtab, vtrCurrent)); // 设置表名,同名不做转化 Map<String, Field> tableNames = new HashMap<String, Field>(1); tableNames.put(vtab, null); targetDb.setTableNames(tableNames); return new MatcherResult(Arrays.asList(targetDb), new HashMap<String, Comparative>(), new HashMap<String, Comparative>()); } /** * 没有分库分表的逻辑表,先从dbIndex中获取映射的库,没有则返回默认的库 * * @param vtab * @param vtrCurrent * @return */ private String getDefaultDbIndex(String vtab, VirtualTableRoot vtrCurrent) { Map<String, String> dbIndexMap = vtrCurrent.getDbIndexMap(); if (dbIndexMap != null && dbIndexMap.get(vtab) != null) { return dbIndexMap.get(vtab); } return vtrCurrent.getDefaultDbIndex(); } protected ComparativeMapChoicer generateComparativeMapChoicer(String condition) { Map<String, Comparative> comparativeMap = ComparativeStringAnalyser.decodeComparativeString2Map(condition); return new SimpleComparativeMapChoicer(comparativeMap); } class SimpleComparativeMapChoicer implements ComparativeMapChoicer { private Map<String, Comparative> comparativeMap = new HashMap<String, Comparative>(); public SimpleComparativeMapChoicer(Map<String, Comparative> comparativeMap){ this.comparativeMap = comparativeMap; } public Map<String, Comparative> getColumnsMap(List<Object> arguments, Set<String> partnationSet) { return this.comparativeMap; } public Comparative getColumnComparative(List<Object> arguments, String colName) { return this.comparativeMap.get(colName); } } }