Реализация sharding-jdbc, несколько очень болезненных замечаний

Java Spring

Оригинал: Miss Sister Taste (идентификатор публичной учетной записи WeChat: xjjdog), добро пожаловать, пожалуйста, сохраните источник для перепечатки. Любое воспроизведение, которое не содержит этого утверждения, является плагиатом.

существует«Подбиблиотека и подтаблица»? Отбор и процесс должны быть осторожными, иначе все выйдет из-под контроля»., мы говорим о драйверном слоеsharding-jdbc. Открытый исходный код достиг этого уровня, что уже здорово, в отличие отtddlстал евнухом. Но есть еще дыры.

Но нельзя винить фреймворк, ведь есть SQL, которые могут понять только программы и призраки.

<select id="getCodes" 
    resultMap="BaseResultMap" 
    parameterType="java.util.Map">
    <foreach collection="orderCodes" 
        index="index" 
        item="item" 
        open="" 
        separator="union all"
        close="">
        select
      	<include refid="Base_Column_List"/>
       	from order
       	where  orderCode =  #{item}
    </foreach>
</select>

неподдерживаемая операция

После того, как база данных разделена на таблицы, она становится кастрированной базой данных. Многие функции SQL не поддерживаются и нуждаются в улучшении другими способами. Версия 3.0.0 описана ниже.

distinct

шардинг-jdbc не поддерживаетdistinct, можно использовать одну таблицуgroup byзаменить. Запрос соединения нескольких таблиц можно заменить существующим

select DISTINCT
        a, b, c, d
        from  table
        where df=0

изменить на

select a, b, c, d
        from  table
        where df=0
        group by a, b, c, d

having

sharding-jdbc не поддерживает наличие, вместо этого вы можете использовать вложенные подзапросы

union

sharding-jdbc не поддерживает объединение (все), его можно разбить на несколько запросов и склеить в программе

О подзапросах

sharding-jdbc не поддерживает отображение одной и той же таблицы в подзапросах, таких как Следующее может ==>

SELECT COUNT(*) FROM (SELECT * FROM t_order o)

Сообщается о следующей ошибке ==>

SELECT COUNT(*) FROM (SELECT * FROM t_order o WHERE o.id IN (SELECT id FROM t_order WHERE status = ?))

Агрегированные функции, включенные в подзапросы, в настоящее время не поддерживаются из-за ограничений слияния.

ноты мибатиса

sharding-jdbc не поддерживает sql в<!-- – >Комментарий, если он должен использоваться, напишите его перед sql или используйте/* */

текстовые поля не поддерживаются

изменить наvarchar, Это баг уже несколько лет, но он не изменился

case when

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

Не должен ли случай, когда функция отключена DBA? мы заполняем дыру

какие-то странные реакции

это возможно

select  a-b from dual  

Но этого не может быть...

select (a-b)c from dual  

Шардинг также не поддерживает следующие формы запросов, а парсинг неупорядочен.

and (1=1 or 1=1)

О нумерации страниц

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

select *  from a limit 10 offset 1000

=======>

Actual SQL:db0 ::: select *  from a limit 1010 offset 0

Об именах таблиц

Имя таблицы должно соответствоватьsharding-jdbcКонфигурация непротиворечива, и рекомендуется использовать строчные буквы. Поскольку маршрут помещается в хэш-карту, он не чувствителен к регистру... Поэтому, если ваш sql неверен, он не будет найден.

Настроить резервирование

Каждая таблица должна быть настроена с информацией о маршрутизации, чтобы ее можно было правильно анализировать.Если у вас слишком много таблиц в вашей библиотеке, файл конфигурации будет увеличиваться до особенно большого размера, даже с тысячами строк. так вymlФайлы конфигурации могут быть разделены в формате .

spring.profiles.include: sharding

Как сканировать несколько библиотек

Например, некоторые временные задачи должны пройти через все библиотеки.

Способ 1: перебрать все библиотеки

Используйте следующий метод, чтобы получить реальный список базы данных

Map<String, DataSource> map = ShardingDataSource.class.cast(dataSource).getDataSourceMap();

Затем логика сканирования выполняется для каждой библиотеки. В этом случае нельзя использовать mybaits и нужно писать нативный jdbc

Способ 2: Траверс по раздельному ключу

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

Как проверить

Подбаза данных и подтаблица очень опасны, потому что после того, как данные будут введены в неправильную базу данных, последующее восстановление будет очень проблематичным. Таким образом, в начале информация о маршрутизации может быть указана в исходной таблице, то есть может быть проверена только точность SQL-маршрутизации. Дождитесь проверки всех маршрутов SQL, а затем переключитесь на настоящую подбазу данных или таблицу.

Убедитесь, что вы можете распечатать SQL

sharding.jdbc.config.sharding.props.sql.show: true

распечатать sql в отдельный файл (logback)

<appender name="SQL" class="ch.qos.logback.core.rolling.RollingFileAppender">
    <file>${LOG_HOME}/sharding.log</file>
    <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
    <fileNamePattern>${LOG_HOME}/backup/sharding.log.%d{yyyy-MM-dd}
    </fileNamePattern>
    <maxHistory>100</maxHistory>
</rollingPolicy>
<encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
    <pattern>${ENCODER_PATTERN}</pattern>
</encoder>
</appender>

Напишите несколько сценариев для проверки файлов SQL. У меня есть общий здесь, вы можете изменить свою логику.

import sys
import re
import getopt

def process(SQL):
    one= "".join(line.strip().replace("\n", " ") for line in SQL)
    place = [m.groups()[0] if m.groups()[0] else m.groups()[1] for m in re.finditer(r"[ ]+(\w+)[ ]*=[ ]*\?|(\?)", one)]

    if len(place):
        mat = re.search(r"::: \[\[(.*)\]\]", one)
        if mat is not None:
            vals = [str(i).strip() for i in str(mat.groups()[0]).split(',')]
            if "splitKey" in place:
                for i in range(len(place)):
                    part = place[i]
                    //这里写你的逻辑
            else:
                 print("no splitKey", one)

SQL = []
def process_line(line):
    global SQL
    if "Actual SQL" in line:
        SQL = []
        SQL.append(line)
    else:
        if line.strip().endswith("]]"):
            SQL.append(line)
            process(SQL)
            SQL = []
        else:
            SQL.append(line)

opts, args = getopt.getopt(sys.argv[1:], "bf")

for op, value in opts:
    if op == "-b":
        print("enter comman mode , such as 'python x.py -b sharding.log > result'")
        with open(args[0], "rb") as f:
            for line in f:
                process_line(line)
    elif op== "-f":
    	print("enter stream scroll mode , such as 'python x.py -f sharding.log '")
        with open(args[0], "rb") as f:
            f.seek(0,2)
            while True:
                last_pos = f.tell()
                line = f.readline()
            if line: process_line(line)

разное

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

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


@RunWith(SpringRunner.class)
@SpringBootTest(classes = App.class)

public class ShardingTest {
    @Autowired
    DataSource dataSource;

    @Test
    public void testGet() {
        try {
            Connection conn = dataSource.getConnection();
            PreparedStatement stmt;
            ResultSet rs;
            String sql = new String(Files.readAllBytes(Paths.get("/tmp/a.sql")));

            stmt = conn.prepareStatement(sql);
            rs = stmt.executeQuery();
            printRS(rs);

        } catch (Exception ex) {
            ex.printStackTrace();
        }
    }
    public static void printRS(ResultSet rs) throws Exception {
        ResultSetMetaData rsmd = rs.getMetaData();
        int columnsNumber = rsmd.getColumnCount();
        while (rs.next()) {
            for (int i = 1; i <= columnsNumber; i++) {
                if (i > 1) System.out.print(",  ");
                String columnValue = rs.getString(i);
                System.out.print(columnValue + " " + rsmd.getColumnName(i));
            }
            System.out.println("");
        }
    }
}

Набор систем с открытым исходным кодом для учебных целей, добро пожаловать в звезду:GitHub.com/star hotel о, хорошо/неплохо…. Он включает в себя сложный бизнес ToB, бизнес с высокой степенью параллелизма в Интернете, приложение кэширования, DDD, руководство по микросервисам. Управляемый моделью, управляемый данными. Поймите путь эволюции крупномасштабных сервисов, навыки кодирования, изучите Linux и настройте производительность. Помощь Docker/k8s, мониторинг, сбор логов, изучение промежуточного ПО. Front-end технология, back-end практика и т.д. Основная техника:SpringBoot+JPA+Mybatis-plus+Antd+Vue3.

Команды со спецификациями SQL довольны, а подтаблицы подбаз данных очень просты. А SQL с сотнями строк и разными сложными функциями можно расковырять только пошагово.

Сказав это, если бы не особенность дел и поддержка устаревшего бизнеса, кто бы использовал это, чтобы разделить вещи, которые не похожи на людей, и призраки, похожие на призраков.

Об авторе:Мисс сестра вкус(xjjdog), публичная учетная запись, которая не позволяет программистам идти в обход. Сосредоточьтесь на инфраструктуре и Linux. Десять лет архитектуры, десятки миллиардов ежедневного трафика, обсуждение с вами мира высокой параллелизма, дающие вам другой вкус. Мой личный WeChat xjjdog0, добро пожаловать в друзья для дальнейшего общения.​