предисловие
С увеличением объема системных данных, говоря об архитектуре базы данных и оптимизации базы данных, мы неизбежно слышим термины «подбаза данных» и «подтаблица».
Конечно, существует множество методологий для подбаз данных и подтаблиц, таких как вертикальное разделение и горизонтальное разделение, а также множество продуктов промежуточного программного обеспечения, таких как MyCat и ShardingJDBC.
Выбор подходящего метода разделения в соответствии с бизнес-сценарием, а затем выбор знакомой платформы с открытым исходным кодом может помочь нам завершить работу по разделению данных, связанную с проектом.
В этой статье не ставится задача подробного обсуждения этих методологий и фреймворков с открытым исходным кодом, автор хочет обсудить другой сценарий:
Если в системе не так много таблиц, которые нужно разделить, одна или несколько, то стоит ли внедрять какие-то относительно сложные промежуточные продукты, тем более, если мы мало знаем об их принципах, то уверены ли мы в их управлении они?
Исходя из этого, если в вашей системе есть небольшое количество таблиц, которые необходимо разделить, и нет выделенных ресурсов для изучения компонентов с открытым исходным кодом, то мы можем реализовать простой плагин подтаблицы подбазы данных самостоятельно; Конечно, если ваша система более сложная, если объем бизнеса большой, безопаснее использовать компоненты с открытым исходным кодом или самостоятельно разработанные командой компоненты для решения этой проблемы.
1. Принцип
Дело о подбиблиотеке и подтаблице просто и просто, но очень сложно, когда сложно...
Простой, потому что его основной процесс относительно ясен. Это анализ оператора SQL, а затем переписывание или маршрутизация его к реальной таблице базы данных в соответствии с предварительно настроенными правилами;
Сложность заключается в том, что операторы SQL сложны и гибки, например такие операции, как разбиение по страницам, дедупликация, сортировка, группировка, агрегирование и связанные запросы, а также способы их правильного анализа.
Так что даже еслиShardingJDBC
, а поддерживаемые и неподдерживаемые элементы также уточняются на официальном сайте.
Во-вторых, конфигурация аннотации
По сравнению со сложными файлами конфигурации мы используем более легкую аннотированную конфигурацию, которая определяется следующим образом:
@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface Sharding {
String tableName(); //逻辑表名
String field(); //分片键
String mode(); //算法模式
int length() default 0; //分表数量
}
Итак, где его использовать? Например, если нашу пользовательскую таблицу нужно разделить на таблицы, то отметьте это на объекте сущности «Пользователь».
@Data
@Sharding(tableName = "user",field = "id",mode = "hash",length = 16)
public class User {
private Long id;
private String name;
private String address;
private String tel;
private String email;
}
Это означает, что у меня всего пользовательских таблиц 16. По идентификатору пользователя я использую алгоритм Hash для вычисления его позиции.
Конечно, у нас есть не только хеш-алгоритм, но и возможность определения по диапазону дат.
@Data
@Sharding(tableName = "car",field = "creatTime",mode = "range")
public class Car {
private long id;
private String number;
private String brand;
private String creatTime;
private long userId;
}
3. Алгоритм фрагментации
Здесь автор реализует два метода шардинга, то естьHashAlgorithm和RangeAlgorithm
.
1. Фрагментация диапазона
Если в вашей системе используется разделение горячих и холодных данных, мы можем разнести данные разных месяцев по разным таблицам в соответствии с датой.
Например, время создания автомобиля2019-12-10 15:30:00
, эти данные будут присвоеныcar_201912
подойдите к этому столу.
Мы можем перехватить часть времени года и месяца, а затем добавить имя логической таблицы.
public class RangeAlgorithm implements Algorithm {
@Override
public String doSharding(String tableName, Object value,int length) {
if (value!=null){
try{
DateUtil.parseDateTime(value.toString());
String replace = value.toString().substring(0, 7).replace("-", "");
String newName = tableName+"_"+replace;
return newName;
}catch (DateException ex){
logger.error("时间格式不符合要求!传入参数:{},正确格式:{}",value.toString(),"yyyy-MM-dd HH:mm:ss");
return tableName;
}
}
return tableName;
}
}
2. хеш-фрагментация
Алгоритм хеширования в срезе, мы можем сначала определить количество таблиц не степени 2. Если нет, то проходим индексным арифметическим способом, если да, то получаем бит по индексному режиму работы. Конечно, это источник, о котором HashMap узнал.
public class HashAlgorithm implements Algorithm {
@Override
public String doSharding(String tableName, Object value,int length) {
if (this.isEmpty(value)){
return tableName;
}else{
int h;
int hash = (h = value.hashCode()) ^ (h >>> 16);
int index;
if (is2Power(length)){
index = (length - 1) & hash;
}else {
index = Math.floorMod(hash, length);
}
return tableName+"_"+index;
}
}
}
4. Перехватчик
Алгоритм конфигурации и шардинга уже есть, а самое главное — самое главное. Здесь мы используемMybatis拦截器
Используйте их.
Все мы, кто все время занимался CRUD, знают, что бизнес-SQL точно не уйдет из их области. Среди них наша функция удаления обычно является логическим удалением в бизнесе, поэтому в основном не будет операции DELETE.
Напротив, добавление и изменение SQL относительно просто и в фиксированном формате, а запросы SQL часто более гибкие и сложные. Поэтому автор определяет здесь два перехватчика.
Однако до введения перехватчика у нас есть основания знать две другие вещи: SQL синтаксический анализатор и процессор алгоритма нарезки.
1, JSQLPARSER
JSqlParser
Отвечает за синтаксический анализ операторов SQL и преобразование их в иерархию классов Java. Мы можем посмотреть на простой пример, чтобы понять это.
public static void main(String[] args) throws JSQLParserException {
String insertSql = "insert into user (id,name,age) value(1001,'范闲',20)";
Statement parse = CCJSqlParserUtil.parse(insertSql);
Insert insert = (Insert) parse;
String tableName = insert.getTable().getName();
List<Column> columns = insert.getColumns();
ItemsList itemsList = insert.getItemsList();
System.out.println("表名:"+tableName+" 列名:"+columns+" 属性:"+itemsList);
}
输出: 表名:user 列名:[id, name, age] 属性:(1001, '范闲', 20)
Мы видим, что,JSqlParser
Информация о синтаксисе SQL может быть проанализирована. Соответственно, мы также можем изменить содержимое объекта, чтобы достичь цели изменения оператора SQL.
2. Алгоритмический процессор
У нас есть несколько алгоритмов шардинга, и какой из них следует вызывать, определяется во время выполнения программы. Итак, мы используем карту, чтобы сначала зарегистрировать алгоритм, а затем вызвать его в соответствии с режимом сегментирования. Это также воплощение паттерна стратегии.
@Component
public class AlgorithmHandler {
private Map<String, Algorithm> algorithm = new HashMap<>();
@PostConstruct
public void init(){
algorithm.put("range",new RangeAlgorithm());
algorithm.put("hash",new HashAlgorithm());
}
public String handler(String mode,String name,Object value,int length){
return algorithm.get(mode).doSharding(name, value,length);
}
}
3, перехватчик
Как мы знаем, MyBatis позволяет перехватывать вызовы в определенный момент выполнения отображаемого оператора.
Если вы не знакомы с его принципом, то можете сначала прочитать статью автора:Принцип действия перехватчика Mybatis.
В целом его процесс выглядит следующим образом:
- пройти через
Mybatis
Перехватить выполняемый SQL; - пройти через
JSqlParser
Разобрать SQL, получить имя логической таблицы и т.д.; - Вызовите алгоритм шардинга, чтобы получить настоящее имя таблицы;
- Измените SQL и измените
BoundSql
; -
Mybatis
Выполните измененный SQL для достижения цели.
Например, дляinsert
заявление иupdate
Заявление, его основной код выглядит следующим образом:
5. Запрос и пейджинг
На самом деле, добавление и изменение относительно просты, чем сложнее оператор запроса.
Однако наш подключаемый модуль не обязательно должен удовлетворять всем запросам, но его можно расширять и модифицировать в соответствии с реальными бизнес-сценариями.
Тем не менее, функция пейджинга в основном неизбежна. братьPageHelper
Например, его принцип также черезMybatis
Перехватчик для достижения. Если это с нашим плагином шардинга, может возникнуть конфликт.
Поэтому в плагине подтаблицы автор также интегрирует функцию пейджинга, которая в принципе аналогичнаPageHelper
то же самое, но не используя его напрямую. Кроме того, для запроса наличие ключа сегмента в условии запроса также является критическим местом.
1. Запрос
В алгоритме диапазона нам нужно запрашивать данные только за определенный месяц или последние месяцы; в алгоритме хеширования нам каждый раз требуется первичный ключ.
Однако второе условие часто не устанавливается, и бизнес-сторона не может каждый раз встречать первичный ключ.
Ввиду этой ситуации мы можем только пройтись по всем таблицам, запросить данные, соответствующие условиям, а затем суммировать и вернуть;
2. Пейджинг
Как упоминалось выше, плагин интегрирует функцию пейджинга для реализации процесса иPageHelper
То же самое, но не используется напрямую из-за конфликтов.
6. Другие
На самом деле, когда я подумал о названии этой статьи, я был очень огорчен. так как分库分表
Это слово в отрасли, но плагин в этой статье не включает подбиблиотеки, а только работу с подтаблицами, но в центре внимания этой статьи находится идея, и, наконец, она называется分库分表
Пожалуйста, прости меня, пожалуйста, не называйте меня титул вечеринка ~
Из-за нехватки места в статье немного кода, если вам интересно, вы можете перейти наhttps://github.com/taoxun/sharding
Получить полную демоверсию.
Авторский код включает в себя несколько тестовых случаев и SQL для создания таблицы.После создания таблицы вы можете запустить проект напрямую.