Как реализовать плагин подтаблицы подбазы данных

Java

предисловие

С увеличением объема системных данных, говоря об архитектуре базы данных и оптимизации базы данных, мы неизбежно слышим термины «подбаза данных» и «подтаблица».

Конечно, существует множество методологий для подбаз данных и подтаблиц, таких как вертикальное разделение и горизонтальное разделение, а также множество продуктов промежуточного программного обеспечения, таких как 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. Запрос

В алгоритме диапазона нам нужно запрашивать данные только за определенный месяц или последние месяцы; в алгоритме хеширования нам каждый раз требуется первичный ключ.

Однако второе условие часто не устанавливается, и бизнес-сторона не может каждый раз встречать первичный ключ.

Ввиду этой ситуации мы можем только пройтись по всем таблицам, запросить данные, соответствующие условиям, а затем суммировать и вернуть;

Недостатком этого подхода становится очевидной плохой производительностью. Другим распространенным способом является то, что вы можете запрашивать взаимосвязь сопоставления с помощью ключа SHARD, сначала найдите значения поля Kard Key на основе критериев поиска в запросе, затем запрос на основе ключей Shard.

2. Пейджинг

Как упоминалось выше, плагин интегрирует функцию пейджинга для реализации процесса иPageHelperТо же самое, но не используется напрямую из-за конфликтов.

6. Другие

На самом деле, когда я подумал о названии этой статьи, я был очень огорчен. так как分库分表Это слово в отрасли, но плагин в этой статье не включает подбиблиотеки, а только работу с подтаблицами, но в центре внимания этой статьи находится идея, и, наконец, она называется分库分表Пожалуйста, прости меня, пожалуйста, не называйте меня титул вечеринка ~

Из-за нехватки места в статье немного кода, если вам интересно, вы можете перейти наhttps://github.com/taoxun/shardingПолучить полную демоверсию.

Авторский код включает в себя несколько тестовых случаев и SQL для создания таблицы.После создания таблицы вы можете запустить проект напрямую.