Некоторое время назад мне поставили задачу написать сервис, который вставляет данные в ClickHouse. Моя команда использует Kotlin и Spring Framework, поэтому я решил попробовать Spring Data JDBC в качестве инфраструктуры ORM для ClickHouse. После некоторого исследования я обнаружил, что ClickHouse имеет интерфейс MySql. Таким образом, вероятно, Spring Data JDBC может общаться с ClickHouse с помощью драйвера MySql.

К сожалению, Spring Data JDBC не работает с ClickHouse из коробки с помощью драйвера MySql. Прежде чем этот подход заработает, необходимо решить несколько проблем.

Эта статья о преодолении проблем, с которыми я столкнулся при выполнении задачи, и их решениях.

Обновление: после написания этой статьи я узнал о диалекте ClickHouse для Spring Data JDBC. Более правильным кажется использование ClickHouse из Spring Data. Изучите эту библиотеку, прежде чем реализовывать мой подход.

Заявление об ограничении ответственности: я пишу о редком случае использования ClickHouse. ClickHouse - это база данных OLAP, которую нельзя использовать в качестве базы данных OLTP, поэтому, если вы не уверены, что этот подход подходит для вас, не повторяйте его. ClickHouse не поддерживает UPDATE / DELETE и многие другие операторы SQL, будьте осторожны при выборе ClickHouse для своего проекта.

Демонстрационный проект

В этой статье я использую Kotlin, Spring Boot и официальный образ докера ClickHouse. Вы можете найти исходный код на моем GitHub в этом репо. В файле README.MD есть руководство, объясняющее, как запустить и протестировать демонстрационный проект.

Схема API и БД для демонстрационного проекта

Я создал простой API и простую схему БД в демонстрационном проекте для демонстрации основных принципов. В моем API есть только два метода: создать элемент и получить все элементы, потому что ClickHouse не поддерживает операции обновления и удаления, поэтому я не могу реализовать все методы CRUD.

DataItem - моя модель данных для items таблицы. Элементы из таблицы items будут сопоставлены с DataItem.

Ниже приведены конечные точки для моего API:

POST v1/demo/item
GET v1/demo/item

Метод POST создаст новый элемент с DataItem моделью, а метод GET вернет все элементы из таблицы items.

Давайте посмотрим на проблемы, с которыми я столкнулся, и способы их решения.

Проблема 1. Транзакция

Spring Data выполняет транзакции фиксации после каждого запроса, но ClickHouse не поддерживает транзакции, поэтому исключение будет выдано во время выполнения запросов к ClickHouse.

Чтобы решить эту проблему, я отключил фиксацию транзакций, заменив класс PlatformTransactionManager пустыми методами commit и rollback.

Проблема 2. Уровень ведения журнала отладки

Драйвер MySql выйдет из строя, за исключением случаев, когда для Spring Data JDBC включен уровень DEBUG. Это происходит из-за того, что драйвер попытался выполнить команду WARNINGS, чтобы получить дополнительную информацию для отладки из БД, но ClickHouse не поддерживает этот оператор.

Чтобы решить эту проблему, я установил уровень регистратора на INFO для регистратора Spring Data JDBC.

<logger name="org.springframework.jdbc" level="INFO" />

Проблема 3. Тип данных массива

MySql не поддерживает тип данных массива, поэтому драйвер MySql выдает исключение, когда я сохраняю список или массив в БД.

Чтобы решить эту проблему, я создал настраиваемую оболочку для типа данных списка и настраиваемые преобразователи для настраиваемой оболочки.

Не забудьте зарегистрировать пользовательские конверсии.

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

Проблема 4. Генерация первичного идентификатора

ClickHouse не поддерживает автоматическое увеличение типа данных для идентификатора. ClickHouse предполагает, что поле ID присваивается пользователем. Проблема возникает, когда Spring Data пытается обновить элемент вместо создания нового, если вы заполнили поле ID элемента в своем коде.

Чтобы решить эту проблему, я унаследовал свою модель от интерфейса Persistable и переопределил метод isNew, чтобы он всегда возвращал true.

Вывод

Как видите, при работе с ClickHouse из Spring Data JDBC возникают некоторые трудности. К счастью, все трудности можно решить, и вы можете с удовольствием вставлять данные в ClickHouse с помощью мощной библиотеки ORM, не сопоставляя свои сущности с операторами SQL вручную.

Спасибо за чтение. Я надеюсь, что это было полезно. Если у вас есть вопросы, не стесняйтесь оставлять ответ.

Ресурсы

  1. Исходный код демонстрационного проекта
  2. Интерфейс ClickHouse MySql