Please wait. This can take some minutes ...
Many resources are needed to download a project. Please understand that we have to compensate our server costs. Thank you in advance.
Project price only 1 $
You can buy this project and download/modify it how often you want.
org.mayanjun.mybatisx.dal.sharding.NameMatrix Maven / Gradle / Ivy
/*
* Copyright 2016-2018 mayanjun.org
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.mayanjun.mybatisx.dal.sharding;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.apache.commons.lang3.ArrayUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.util.Assert;
import java.io.IOException;
import java.io.Serializable;
import java.util.*;
/**
* NameMatrix:描述了实体和数据规模的对应关系
*
* @author mayanjun(23/09/2016)
*/
public class NameMatrix implements Serializable {
private static final ObjectMapper OBJECT_MAPPER;
private static final TypeReference>> MATRIX_TPYE_REFERENCE = new TypeReference>>() {};
static {
OBJECT_MAPPER = new ObjectMapper();
}
/**
* KEY: 实体名称
* VALUE: Scale 对应的数据库名称和表名称
*/
private Map> matrix;
/**
* 一个实体映射的所有数据库名称和表名称,方便用来做全库全表扫描
* KEY: 实体名称
* VALUE: 数据库名称:[表名称]
*/
private Map>> mergedNameMap;
/**
* mergedNameMap value 的序列化形式,为了在返回时复制
*/
private Map mergedNameMapJson;
/**
* 存储当前调用的表名
*/
private final ThreadLocal tableName;
public NameMatrix(List metadatas) {
this.tableName = new ThreadLocal();
this.mergedNameMap = new TreeMap>>();
this.mergedNameMapJson = new HashMap();
initMatrix(metadatas);
}
private void initMatrix(List metadatas) {
if (metadatas == null || metadatas.isEmpty()) {
throw new IllegalArgumentException("metadatas may not be empty");
}
this.matrix = new HashMap>();
for (ScaleOutMetadata metadata : metadatas) {
String entityName = metadata.getEntityName();
try {
Long scale = metadata.getScale();
if (scale == null) throw new IllegalArgumentException("scale may not be null");
Map> dtMap = OBJECT_MAPPER.readValue(metadata.getMatrixJson(), MATRIX_TPYE_REFERENCE);
DTNames names = this.new DTNames(scale, dtMap);
TreeMap scaleTable = matrix.get(entityName);
if(scaleTable == null) {
scaleTable = new TreeMap();
matrix.put(entityName, scaleTable);
}
if(scaleTable.containsKey(scale)) {
String message = String.format("Duplicated scale %d in entity %s", scale, entityName);
throw new IllegalArgumentException(message);
}
scaleTable.put(scale, names);
mergeNameMap(entityName, names);
} catch (IOException e) {
e.printStackTrace();
}
}
}
/**
* 获取指定实体名称下的所有数据库名称和表名称
* @param entityName
* @return
*/
public Map> getDataBaseNames(String entityName) {
String json = mergedNameMapJson.get(entityName);
if(json != null) {
try {
return OBJECT_MAPPER.readValue(json, MATRIX_TPYE_REFERENCE);
} catch (IOException e) {
e.printStackTrace();
}
return null;
}
Map> map = mergedNameMap.get(entityName);
if(map != null) {
try {
String json1 = OBJECT_MAPPER.writeValueAsString(map);
mergedNameMapJson.put(entityName, json1);
return getDataBaseNames(entityName);
} catch (JsonProcessingException e) {
e.printStackTrace();
}
}
return null;
}
/**
* 合并同一个实体在数据库中被存储的数据库名称和表名称
* @param entityName
* @param names
*/
private void mergeNameMap(String entityName, DTNames names) {
Map> map = this.mergedNameMap.get(entityName);
if(map == null) {
map = new HashMap>();
mergedNameMap.put(entityName, map);
}
Iterator> iterator = names.nameMap.entrySet().iterator();
while (iterator.hasNext()) {
Map.Entry entry = iterator.next();
String dbName = entry.getKey();
Set tableNames = map.get(dbName);
if(tableNames == null) {
tableNames = new HashSet();
map.put(dbName, tableNames);
}
for(String s : entry.getValue()) {
tableNames.add(s);
}
}
}
private String mergeredMapToString() {
StringBuilder sb = new StringBuilder();
Iterator>>> it = mergedNameMap.entrySet().iterator();
while (it.hasNext()) {
Map.Entry>> e = it.next();
sb.append(e.getKey() + ":\r\n");
Iterator>> it2 = e.getValue().entrySet().iterator();
while (it2.hasNext()) {
Map.Entry> e2 = it2.next();
sb.append("\t" + e2.getKey() + ": ").append(e2.getValue().toString() + "\r\n");
}
sb.append("-----------------\r\n");
}
return sb.toString();
}
public static String serialize(Map> matrix) {
Assert.isTrue(matrix != null && !matrix.isEmpty(), "Matrix map can not be empty");
try {
Map> matrix0 = new TreeMap>();
for(Map.Entry> entry : matrix.entrySet()) {
Set set = entry.getValue();
if(set != null) {
set = new TreeSet(set);
matrix0.put(entry.getKey(), set);
}
}
return OBJECT_MAPPER.writeValueAsString(matrix0);
} catch (JsonProcessingException e) {
e.printStackTrace();
}
return null;
}
/**
* 解析字符串并序列化分库分表源数据。数据格式:dbName:t1,t2,...,tN;db2=t1,t2,...,tN;...
* @param matrix
* @return
*/
public static String serialize(String matrix) {
Assert.isTrue(StringUtils.isNotBlank(matrix), "Matrix string can not be empty");
String s0[] = matrix.split(";");
Map> matrixMap = new HashMap>(s0.length);
for(String s : s0) {
String s1[] = s.split(":");
if(s1.length == 2) {
String key = StringUtils.deleteWhitespace(s1[0]);
String value = s1[1];
String ts[] = value.split(",");
if(ts.length > 0) {
Set set = new HashSet();
for(String t : ts) set.add(StringUtils.deleteWhitespace(t));
matrixMap.put(key, set);
}
}
}
return serialize(matrixMap);
}
@Override
public String toString() {
StringBuilder sb = new StringBuilder();
if(!this.matrix.isEmpty()) {
Iterator>> it = matrix.entrySet().iterator();
while (it.hasNext()) {
Map.Entry> entry = it.next();
sb.append(entry.getKey() + ":\r\n");
TreeMap map = entry.getValue();
Iterator> it1 = map.entrySet().iterator();
while (it1.hasNext()) {
Map.Entry entry1 = it1.next();
sb.append("\t" + entry1.getKey() + " > " + entry1.getValue().toString() + "\r\n");
}
//sb.append("----------------------\r\n");
}
sb.append("================ Merged Name Map ===============\r\n");
sb.append(mergeredMapToString());
return sb.toString();
} else {
return "null";
}
}
/**
* 此处TableName顺便也算出来
* @param scale
* @param entityName
* @return
*/
public String getDataBaseName(long scale, String entityName) {
TreeMap map = matrix.get(entityName);
if(map != null) {
Map.Entry entry = map.floorEntry(scale);
DTNames names = entry.getValue();
Long index = scale % names.dbNames.length;
String dbName = names.dbNames[index.intValue()];
// 计算TableName
String[] tableNames = names.nameMap.get(dbName);
Long tableIndex = scale % tableNames.length;
this.tableName.set(tableNames[tableIndex.intValue()]);
return dbName;
}
throw new IllegalArgumentException("scale map not found: scale=" + scale + ", entityName=" + entityName);
}
public String getTableName() {
return tableName.get();
}
////////////////////////////////////////////////////////////////
/**
* 描述了数据库名称和表名称的对应关系
*/
class DTNames {
private long scale;
private String dbNames[];
private Map nameMap;
public DTNames(long scale, Map> nameMap) {
if(scale < 0) throw new IllegalArgumentException("scale can not be a negative integer");
this.scale = scale;
init(nameMap);
}
private void init(Map> nameMap) {
if(nameMap == null || nameMap.isEmpty()) throw new IllegalArgumentException("NameMap can not be empty:");
Map map = new TreeMap();
Iterator>> iterator = nameMap.entrySet().iterator();
while (iterator.hasNext()) {
Map.Entry> entry = iterator.next();
String name = entry.getKey();
Set set = new TreeSet(entry.getValue());
String tableNames[] = new String[set.size()];
set.toArray(tableNames);
map.put(name, tableNames);
}
this.nameMap = map;
Set dbNamesSet = this.nameMap.keySet();
this.dbNames = new String[dbNamesSet.size()];
dbNamesSet.toArray(dbNames);
}
@Override
public String toString() {
StringBuilder sb = new StringBuilder("scale=" + scale + ",dbNames=[");
for(int i = 0; i < dbNames.length; i++) {
sb.append(dbNames[i]);
if(i < dbNames.length - 1) sb.append(",");
}
sb.append("], matrix={");
Iterator> it = nameMap.entrySet().iterator();
while (it.hasNext()) {
Map.Entry entry = it.next();
sb.append(entry.getKey()).append("=").append(ArrayUtils.toString(entry.getValue())).append(",");
}
int lastIndex = sb.length() - 1;
if(sb.charAt(lastIndex) == ',') sb.setCharAt(lastIndex, '}');
return sb.toString();
}
}
}